faloi
faloi

Reputation: 401

MongoDb: How to unset attribute from nested arrays?

I'm trying to remove an attribute from a triple-nested array without success. Here is an example of the data I want to remove:

Controls: [
    {    
        Name: 'ControlNumberOne',
        Submit: {   
            Executes: [
                {
                    Name: 'execute',
                    Type: 0
                },
                {
                    Name: 'anotherExecute',
                    Type: 0
                }
            ]
        }
    },
    {    
        Name: 'ControlNumberTwo',
        Submit: {   
            Executes: [
                {
                    Name: 'anotherFromAnotherControl',
                    Type: 1
                }
            ]
        }
    }

]

I tried the following update queries but none of them worked:

However, if I execute db.Page.find('Controls.Submit.Executes.Type': { $exists : true } }) it does return all the Executes that still have a Type attribute.

Can this be achieved? Thanks!

Upvotes: 6

Views: 3847

Answers (2)

ndmhta
ndmhta

Reputation: 536

If anyone is still looking for an answer (like me), here it is.

With MongoDB version 3.6+, it is now possible to use the positional operator to update all items in an array, including the deeper nested level. See official documentation here.:

db.getCollection('xxx').update(
   {'Controls.Submit.Executes.Type': { $exists : true },
   { $unset : {'Controls.$[].Submit.Executes.$[].Type' : 1}}
)

This code is tested and works well with MongoDB CLI, RoboMongo and Mongo-Java driver.

Upvotes: 9

ronasta
ronasta

Reputation: 2569

Querying and updating of nested arrays is not (yet) supported by MongoDB commands directly, this has to be done on the client side:

  • read the document into a variable
  • manipulate the array
  • update the document, rewriting the entire array

See this issue on Jira: https://jira.mongodb.org/browse/SERVER-831 and this thread on stackoverflow: Mongo update of subdocs

Given your example, this would look like this:

db.xx.find(
    {'Controls.Submit.Executes.Type': { $exists : true } }
).forEach( function(doc) {
    doc.Controls.forEach( function(c) {
        c.Submit.Executes.forEach( function(e) {
            if ( e.Type != undefined ) delete e.Type;        
        });
    });
    db.xx.update({_id: doc._id},{$set:{Controls:doc.Controls}});
});

and the result is:

> db.xx.findOne()
{
    "Controls" : [
        {
            "Name" : "ControlNumberOne",
            "Submit" : {
                "Executes" : [
                    {
                        "Name" : "execute"
                    },
                    {
                        "Name" : "anotherExecute"
                    }
                ]
            }
        },
        {
            "Name" : "ControlNumberTwo",
            "Submit" : {
                "Executes" : [
                    {
                        "Name" : "anotherFromAnotherControl"
                    }
                ]
            }
        }
    ],
    "_id" : ObjectId("5159ff312ee0f7d445b03f32")
}

Upvotes: 5

Related Questions