MongoDB not updating subdocument within double-nested array (using Mongoose FindByIdAndUpdate) - EXACT POSITION KNOWN

4.3k views Asked by At

I have a document structure that's roughly similar to the following:

{
    "_id": "theIdOfThisObject",
    "subdoc": {
        "array": [
            [
                {
                    "parameters": {},
                    "winner": null,
                    "participants": [
                        "Person1",
                        "Person2"
                    ]
                },
                {
                    "parameters": {},
                    "winner": null,
                    "participants": [
                        "Person3",
                        "Person4"
                    ]
                }
            ],
            []
        ]
    },
}

I am entirely trying to replace one of the subdocuments within the nested array. I do not need to search for it - i know the exact position.

For example, I am trying to replace the first subdocument with

                    "parameters": {"frog":20},
                    "winner": "Person1",
                    "participants": [
                        "Person1",
                        "Person2"
                    ]

which we'll say is saved as an object called newObject.

I expect the following code to work (and Model is a real Mongoose Model):

Model.findByIdAndUpdate('theIdOfThisObject',{$set: {'subdoc.array.0.0':newObject}}, function(err,doc){
  console.log('doc is returned, but nothing is updated')
});

I have no idea what is going on and why this isn't working. Does anybody have any suggestions? I have been using MongoDB's native node driver for a very long time (3 years), but Mongoose is fairly new to me.

EDIT - adding schema as per comment request

The schema is pretty straightforward. looks as follows:

var Schema   = new mongoose.Schema({
    subdoc: {
        array: [{}]
    }
});

There's other fields in there, but this is the only one that matters in this case. My understanding is that having the Schema have a [{}] means that there will be an array of any kind of JSON arrangement. The Schema also lets me initially set the subdocument in question - it just doesn't let me update it for whatever reason.

3

There are 3 answers

2
thisissami On BEST ANSWER

I have figured out the issue. Apparently when using the Mixed Schema type, (which is the same as {}) with Mongoose, updating a subfield within the object is a 2 step process. You can't just use findByIdAndUpdate().

You must first use fineById(), grab the document in the callback, run markModified() on the document in question (passing in the path to the subdocument), and then finally save said document. Here's the code:

Model.findById('theIdOfThisObject', function(err,doc){
        //update the proper subdocument
        doc.subdoc.array[0][0] = newObject;
        //then mark it as modified and save it
        doc.markModified('brackets.rounds');
        //save the model
        doc.save(callback);
});
1
Mario On

Maybe there are two things here.

First, in your sheme i recommend that you use

var Schema   = new mongoose.Schema({
subdoc: {
    array: [{type: Schema.Types.Mixed}]
}});

so that it is rightly defined as there can be anything.

Or the second thing that might could be missing. If the existing entry doesn't exist you have to set the option upsert :true that new entrys will also get inserted.

Model.findByIdAndUpdate('theIdOfThisObject',{$set: {'subdoc.array.0.0':newObject}}, {upsert : true},console.log);
0
Abdelilah On

I had the same problem and I can confirm, this line was the fix:

doc.markModified('brackets.rounds');