Home > Net >  Look up and create or update object inside array
Look up and create or update object inside array

Time:11-01

I am currently trying to setup a schema for custom Discord guild commands:

const GuildCommandsSchema = new mongoose.Schema({
    _id: String,
    commands: [
        {
            name: {
                type: String,
                unique: true,
                required: true,
            },
            action: {
                type: String,
                required: true,
            },
            author: {
                type: String,
                required: true,
            },
        },
    ],
});

Is this ok, performancewise, or could I improve it? I feel like Mongo would need to look through all commands, since it can't index any commands inside 'commands' even though 'name' is unique.

If that's fine, how can I access the values inside commands? I would need to find the right command via 'name' if it exists, otherwise create it and add/update 'action' 'author'.

I tried something like this:

const updatedCommand = await GuildCommands.findOneAndUpdate(
                { _id },
                {
                    $set: {
                        [`commands.$[outer].name`]: name,
                        [`commands.$[outer].action`]: action,
                        [`commands.$[outer].author`]: author,
                    },
                },
                {
                    arrayFilters: [{ 'outer.name': name }],
                }
            );

Unfortunately that does not create commands if they don't exist.

Thanks for your help

CodePudding user response:

aggregate

db.collection.update({},
{
  $set: {
    "commands.$[c].name": "1",
    "commands.$[c].author": "1",
    "commands.$[c].action": "1"
  }
},
{
  arrayFilters: [
    {
      "c.author": "34"
    }
  ],
  multi: true
})

mongoplayground

CodePudding user response:

To answer my own question:
I changed my Schema to use Maps instead of Arrays for performance improvments and also better model management.

const GuildCommandsSchema = new mongoose.Schema(
    {
        _id: String,
        commands: {
            type: Map,
            of: {
                _id: false,
                name: {
                    type: String,
                    required: true,
                },
                action: {
                    type: String,
                    required: true,
                },
                active: {
                    type: Boolean,
                    required: true,
                    default: true,
                },
                author: {
                    type: String,
                    required: true,
                },
            },
        },
    },
    { versionKey: false }
);

The new query to find and update/create a command is also better imo:

const findCommand = await GuildCommands.findOne({ _id });
if (!action) {
    const getCommand = findCommand.commands.get(name);
    if (getCommand) {
        message.reply(getCommand.action);
    } else {
        message.reply(`Cannot find ${name}`);
    }
} else {
    findCommand.commands.set(name, {
        name,
        action,
        author,
    });
    findCommand.save();
}
  • Related