简体   繁体   中英

Extract variables from json string

Context:

I'm making a Discord bot using the discord.js library and MongoDB (with mongoose). I created a script that can construct messages from data stored in my MongoDB database. For exemple, if an user on my Discord server type ",hello". it will query my database to construct a reply like "Hello to you!".

I store my reply message data in an document like this:

{
    "command": "!hello",
    "content": "Hello to you!"
}

(I voluntary omitted some properties here that are useless in the context of my question)

And retrieve it in my code with something like:

let retrievedReply;
await mongo().then(async mongoose => {
    try {
        let query = {command: message.content};
        retrievedReply = await replySchema.findOne(query);
    } finally {
        mongoose.connection.close();
    }
});
message.reply(retrievedReply.content);

My issue:

Now, imagine I want it to respond "Hello username .".

If I didn't construct my reply using data from mongo I could simply do something like:

message.reply(`Hello ${message.member.nickname}!`);

or

message.reply("Hello " + message.member.nickname + "!");

So, in other words, using backticks and ${} syntax or (but I like it less), splitting my string and concatenate my property value like the second example.

The thing is, we can't store a string inside backticks in json format (used by MongoDB). So even if I build my document like so:

{
    "command": "hello",
    "content": "Hello ${message.member.nickname}!"
}

${message.member.nickname} would not be interpreted like a property value but just like a simple string.

The 1000$ question:

How can I use this property inside my code? I thought about extracting it using regex but it does not change the fact that it will still be a string. Is there a way to "convert" from a string to an usable variable?

EDIT

Since Brettski asked me (rightfully), here is an example of what I want:

message.member.send(`Hello ${message.member}!`);

This message.member property here represent a member object of a Discord guild. It contains a lot of things like its permissions on the guild, its roles, etc. When we use a member object into a message, Discord will make a mention of the member like bellow.

从机器人接收到应用程序的消息

It works the same with other properties like channels for example. Users can then click on those to see informations about the member or to go directly to the channel, etc. I want to be able to use this.

That is correct you will not be able to store a string literal in Mongo or other way.

One though I had is to put a token in your string and then do a replace on it in message.reply() or before it.

example:

const helloCommand = {
  "command": "hello",
  "content": "Hello ~~membernickname~~!"
};

In this example the token to replace is ~~membernickname~~

You can use something like this to do the replace:

const command = JSON.parse(helloCommand)
message.member.send(command.content.replace('~~membernickname~~', message.member));

The resulting string being sent to the send() command is the same. So if the nickname is @brettski, the string 'Hello @brettski' will be sent to the send() command.

In your example:

message.reply(`Hello ${message.member.nickname}!`);

the part:

`Hello ${message.member.nickname}!`

is a string literal ( template literals ). What the function message.reply() ends up getting is 'Hello Nickname' a string. So the replace should work. As a test you can hard code the string used in message.reply() to a known nickname and it should provide the results you expect.

Ok so, @Brettski put me on the right track with the fact that I can use users' or channels' IDs directly as strings within the message and between specific tags.

To reuse the example in my question, I can use this syntax to mention an user:

"<@idOfTheUser>"

What I did is if I want to mention the author of the command in my reply, I put the text in my mongoDB document as so:

const helloCommand = {
  "command": "hello",
  "content": "Hello $member$!"
};

Then, in my code, I can simply use:

message.reply((retrieveReply.content).replace(/\$member\$/g, `<@${message.member.id}>`))

Of course, I wanted to use more properties so I did a function like:

const messageContentReplace = function(content) {
    const replaceableStrings = {
                "$member$": `<@${message.member.id}>`,
                "$memberName$": message.member.displayName,
                "$guild$": message.guild.name
    }
    return content.replace(/(\$member\$)|(\$memberName\$)|(\$guild\$)/g, match => {
        return replaceableStrings[match];
});

(in reality, I did something more complexe because I use an embed message as my response with multiple fields etc... See here about embeds)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM