Reputation: 1345
I have a collection records
like this
{
"recordId" : "5a65d212-774e-4208-8cb4-bf4e92e80898",
"recordName" : "recordABC",
"entries" : [
{
"formId" : "f548684e-31a7-4e63-af5c-4120670f963f",
"formSequence" : 1,
"fieldId" : "element1",
},
{
"formId" : "f548684e-31a7-4e63-af5c-4120670f963f",
"formSequence" : 2,
"fieldId" : "element2",
"value" : "notes"
},
{
"formId" : "f548684e-31a7-4e63-af5c-4120670f963f",
"formSequence" : 1,
"fieldId" : "element3",
"value" : [
{
"originalFileName" : "fileA",
"thumbnail" : "thumbnailA"
},
{
"originalFileName" : "fileB",
"thumbnail" : "thumbnailB"
},
{
"originalFileName" : "fileC",
"thumbnail" : "thumbnailC"
},
{
"originalFileName" : "fileD",
"thumbnail" : "thumbnailD"
}
]
}
]
}
I need to remove the document
{
"originalFileName" : "fileC",
"thumbnail" : "thumbnailC"
}
from record.entries.value
array.
I tried with below query
db.records.update({ "_id" : "5a65d212-774e-4208-8cb4-bf4e92e80898" , $and : [ { "entries.formSequence" : 1} , { "entries.formId" : "f548684e-31a7-4e63-af5c-4120670f963f"} , { "entries.fieldId" : "element3"}]}, { $pull : { "entries.$.value" : { "originalFileName" : "fileC"}}});
It returns WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
There is a one match, but the item with "originalFileName" : "fileC"
is not removed
Whats is wrong with my query ? How to do this ?
Upvotes: 5
Views: 3667
Reputation: 151112
You need to make sure you are matching a specific element in the array when using the positional $
operator in an update statement. $and
does generally not cut it, what you need for multiple fields of an array element is $elemMatch
:
db.records.update(
{
"recordId": "5a65d212-774e-4208-8cb4-bf4e92e80898",
"entries": {
"$elemMatch": {
"formSequence": 1,
"formId" : "f548684e-31a7-4e63-af5c-4120670f963f",
"fieldId" : "element3"
}
}
},
{
"$pull" : {
"entries.$.value" : { "originalFileName" : "fileB"}
}
}
)
This makes sure that the "position" of the matched operator is the one that matches all for the conditions for that elements properties that you specify.
The main problem with $and
in this case ( and also not necessary since you are not asking for multiple conditions on the same field, so it is really an implicit statement, which MongoDB just does ) is that you are not matching the conditions on the same element. All that is being done is making sure that all the conditions actually match somewhere in the document, and therefore in any element.
You could write in this way as well, which will not return the correct result:
db.records.update(
{
"recordId": "5a65d212-774e-4208-8cb4-bf4e92e80898",
"entries.formSequence": 1,
"entries.formId" : "f548684e-31a7-4e63-af5c-4120670f963f",
"entries.fieldId" : "element3"
},
{
"$pull" : {
"entries.$.value" : { "originalFileName" : "fileB"}
}
}
)
Perfectly valid in syntax and the same as what you have written, but of course it does not select the correct element for the result you want in the update statement.
So it is $elemMatch
that makes sure that all of those conditions are present on the same element within the array. This is what you want, as it performs an individual "query" on each element of the array to make sure those conditions match.
Upvotes: 7