Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB: updating an array in array

I seem to be having an issue accessing the contents of an array nested within an array in a mongodb document. I have no problems accessing the first array "groups" with a query like the following...

db.orgs.update({_id: org_id, "groups._id": group_id} , {$set: {"groups.$.name": "new_name"}});

Where I run into trouble is when I try to modify properties of an element in the array "features" nested within the "group" array.

Here is what an example document looks like

     {
        "_id" : "v5y8nggzpja5Pa7YS",
        "name" : "Example",
        "display_name" : "EX1",
        "groups" : [
            {
                "_id" : "s86CbNBdqJnQ5NWaB",
                "name" : "Group1",
                "display_name" : "G1",
                "features" : [
                    {
                        _id      : "bNQ5Bs8BWqJn6CdNa"
                        type     : "blog",
                        name     : "[blog name]"
                        owner_id : "ga5YgvP5yza7pj8nS"
                    }, 
                ]
             },
         ]
     },

And this is the query I tried to use.

db.orgs.update({_id: "v5y8nggzpja5Pa7YS", "groups._id": "qBX3KDrtMeJGvZWXZ", "groups.features._id":"bNQ5Bs8BWqJn6CdNa" }, {$set: {"groups.$.features.$.name":"New Blog Name"}});

It returns with an error message:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 2,
        "errmsg" : "Too many positional (i.e. '$') elements found in path 'groups.$.features.$.name'"
    }
})

It seems that mongo doesn't support modifying arrays nested within arrays via the positional element?

Is there a way to modify this array without taking the entire thing out, modifying it, and then putting it back in? With multiple nesting like this is it standard practice to create a new collection? (Even though the data is only ever needed when the parent data is necessary) Should I change the document structure so that the second nested array is an object, and access it via key? (Where the key is an integer value that can act as an "_id")

groups.$.features.[KEY].name

What is considered the "correct" way to do this?

like image 693
James Avatar asked Jun 11 '15 14:06

James


People also ask

How do I update an entire array in MongoDB?

You can use the updateOne() or updateMany() methods to add, update, or remove array elements based on the specified criteria. It is recommended to use the updateMany() method to update multiple arrays in a collection.

How do I update a nested array in MongoDB?

Update Nested Arrays in Conjunction with $[]The $[<identifier>] filtered positional operator, in conjunction with the $[] all positional operator, can be used to update nested arrays. The following updates the values that are greater than or equal to 8 in the nested grades.

How do I find and update an array of objects in MongoDB?

To perform an update on all embedded array elements of each document that matches your query, use the filtered positional operator $[<identifier>] . The filtered positional operator $[<identifier>] specifies the matching array elements in the update document.

How do I add elements to an array in MongoDB?

If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push . For an example, see Append a Value to Arrays in Multiple Documents. For a list of modifiers available for $push , see Modifiers.


1 Answers

After some more research, it looks like the only way to modify the array within an array would be with some outside logic to find the index of the element I want to change. Doing this would require every change to have a find query to locate the index, and then an update query to modify the array. This doesn't seem like the best way.

Link to a 2010 JIRA case requesting multiple positional elements...

Since I will always know the ID of the feature, I have opted to revise my document structure.

     {
    "_id" : "v5y8nggzpja5Pa7YS",
    "name" : "Example",
    "display_name" : "EX1",
    "groups" : [
        {
            "_id" : "s86CbNBdqJnQ5NWaB",
            "name" : "Group1",
            "display_name" : "G1",
            "features" : {
               "1" : {
                       type     : "blog",
                       name     : "[blog name]"
                       owner_id : "ga5YgvP5yza7pj8nS"
               }, 
            }
         },
     ]
 },

With the new structure, changes can be made in the following manner:

db.orgs.update({_id: "v5y8nggzpja5Pa7YS", "groups._id": "s86CbNBdqJnQ5NWaB"}, {$set: {"groups.$.features.1.name":"Blog Test 1"}});
like image 176
James Avatar answered Nov 07 '22 03:11

James