Search code examples
javascriptnode.jsmongodbmongoose

Saving objects in a nested schema in Mongoose / MongoDB


I'm new to using MongoDB and Mongoose and I have a feeling I'm doing something wrong.

Assume I have the following schema in Mongoose:

const characterSchema = new Schema({
  name: {
    required: true,
    type: String,
  },
});

const gameSchema = new Schema({
  name: {
    required: true,
    type: String,
  },
  characters: [characterSchema],
});

To me, this tells me that I have a one to many relationship where a game has many characters. However, if I perform an update to a character with... await Character.findOneAndUpdate and then run db.characters.find() and db.games.find(), the two entries for the character will be different. Only one of them will have the update.

This tells me that these are two separate instances of the data... And I'm not sure why I'd ever want that. I would prefer to update the model once and have it be reflected everywhere. Am I doing something wrong? Is there a way to write with either the Character model or and instance of game like game.characters[0] and only need to update the data once?

Thank you for your time.


Solution

  • For this scenario, there are two general approaches:

    First, a more scalable approach would be to create an "intermediary" reference schema, serving as a one-to-one relationship between the game and the character --

    // GameCharacter schema
    {
        "character" : {
            type: mongoose.Types.ObjectID,
            ref: 'characters',
            required: true
        },
        "game" : {
            type: mongoose.Types.ObjectID,
            ref: 'games',
            required: true
        }
    }
    

    Second, if you believe the number of character references for a given game will be kept to a relative minimum, you can opt to save the character references within the game object, rather than creating a separate reference schema --

    // Game schema
    {
        ...
        "characters" : [
            {
                type: mongoose.Types.ObjectID,
                ref: 'characters',
                required: true
            }
        ]
    }
    

    In either scenario, you can use aggregate pipelines or populate to grab the nested information from the references.