DEV Community

loading...

Remove and modify nested documents in MongoDB

mfahlandt profile image Mario ・2 min read

I have a rather complex Document Structure to fulfill the approach of have all the data available when you execute one query. However there is the big issue of modifying it.

So lets have a look at our Object that we want to modify


{
    "_id" : ObjectId("5b0bf696cb5dd80010bea0a3"),
    "domains" : [ 
        {
            "_id" : ObjectId("5b0bf696cb5dd80010bea0a4"),
            "DKIMRecordName" : "mailjet._domainkey.example.de.",
            "DKIMRecordValue" : "k=rsa; p=000000000000000000000000",
            "DKIMStatus" : "Not Checked",
            "Domain" : "example.de",
            "IsCheckInProgress" : false,
            "SPFRecordValue" : "v=spf1 include:spf.mailjet.com ?all",
            "SPFStatus" : "Not Checked",
            "emails" : [ 
                {
                    "_id" : ObjectId("5b0bf696cb5dd80010bea0a5"),
                    "CreatedAt" : ISODate("2018-05-28T12:31:18.000Z"),
                    "DNSID" : "2837371580",
                    "Email" : "no-reply@example.de",
                    "EmailType" : "unknown",
                    "Filename" : "",
                    "ID" : "216556",
                    "IsDefaultSender" : false,
                    "Name" : "",
                    "Status" : "Inactive"
                },
                {
                    "_id" : ObjectId("5b0bf696cb5dd45410bea0a5"),
                    "CreatedAt" : ISODate("2018-05-28T12:31:18.000Z"),
                    "DNSID" : "2837371580",
                    "Email" : "newsletter@example.de",
                    "EmailType" : "unknown",
                    "Filename" : "",
                    "ID" : "216556",
                    "IsDefaultSender" : false,
                    "Name" : "",
                    "Status" : "Inactive"
                }
            ]
        }
}


So if you want to modify one of them we will use the following

db.yourCollection.update({'domains.emails.Email': 'no-reply@example.de'},
{ $set: {'email.$.emails':  
    {
                    "_id" : ObjectId("5b0bf696cb5dd80010bea0a5"),
                    "CreatedAt" : ISODate("2018-05-28T12:31:18.000Z"),
                    "DNSID" : "2837371580",
                    "Email" : "no-reply@example.de",
                    "EmailType" : "unknown",
                    "Filename" : "",
                    "ID" : "216556",
                    "IsDefaultSender" : false,
                    "Name" : "",
                    "Status" : "Active"
                }

  },
{multi: true})

Why do we have to put in the whole Object? Sadly we can not use a second positional $ operator. So we have to provide the full nested Document. Additional it MUST be included as part of the Query document, otherwise it would not recognize it. This would throw the Error "The positional operator did not find the match needed from the query."

Also what we can do is a pull operation:

db.yourCollection.update({'email.emails.Email': 'no-reply@example.de'},
{ $pull: {'email.$.emails':  {'Email': 'no-reply@example.de'}}  },
{multi: true})

This will remove the Child Document from the nested Array.

Be aware, the multi: true will not work and you have to run the query multiple times.

Discussion

pic
Editor guide
Collapse
rkristelijn profile image
Remi Kristelijn

I don't think you have to put the whole object, you can set individual properties of one of the elements using a double search param and place the '$set' on the field itself:

using your example above, something like:

db.yourCollection.update({
  _id: ObjectId("5b0bf696cb5dd80010bea0a3"),
  'emails._id': ObjectId("5b0bf696cb5dd80010bea0a5")
}, {'$set': {'emails.$.Email': 'w.white@break.bad'}})

Good to read that '$pull' will remove an element, note that '$push' will add an element

Collapse
luqezman profile image
Lucas Silva

You mean { $pull: {'domain.$.emails': {'Email': 'no-reply@example.de'}} }?

Collapse
ashin2052 profile image
Ashin2052

what is email.emails.Email?