Web User
Web User

Reputation: 7746

Update MongoDB document with nested arrays of sub-documents

I need to update a MongoDB document that looks like this:

{
    "_id" : ObjectId("A"),
    "participant" : "John Doe",
    "roles" : [{
        "roleId" : ObjectId("AA"),
        "responsibilities" : [{
            "_id" : ObjectID("AAA"),
            "name" : "resp 1"
        }, {
            "_id" : ObjectID("AAB"),
            "name" : "resp 2"
        }]
    }, {
        "roleId" : ObjectId("AB"),
        "responsibilities" : []
    }]
}

The updates come in two forms:

Upvotes: 0

Views: 337

Answers (1)

devonj
devonj

Reputation: 1238

Your first update:

db.getCollection('collection').update({}, 
    {
        $pull: {
            'roles': {
                'responsibilities': {$size: 0}
            }
        }
    }, {multi: true})

Basically, removes element of any (this is where multi: true comes in) "roles" array with "responsibilities" being an empty array (or size 0)

Your second update, assuming a "new role" is a role with an empty responsibilities array:

db.getCollection('collection').update(
    {
        'roles': {
            $not: {
                $elemMatch: {
                    'roleId': ObjectId("AC")
                }
            }
        }
    },
    {
        $push: {
            'roles': {
                'roleId': ObjectId("AC"), 
                'responsibilities' : []
            }
        }
    }, {multi: true})

Finds documents that don't have a roles array where an element has an empty responsibilities array, and then pushes a new role with a new ObjectId, or you can specify one yourself.

I've tested this on a small collection of 5 documents and seems to work, let me know if you need any clarification or if it does not work.

It's worth noting that querying an array where you have to iterate through the array $elemMatch is what you're looking for. When modifying and you need to iterate through an array $pull is what you want to use.

Upvotes: 1

Related Questions