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.
Top comments (3)
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:
Good to read that '$pull' will remove an element, note that '$push' will add an element
You mean { $pull: {'domain.$.emails': {'Email': 'no-reply@example.de'}} }?
what is email.emails.Email?