Reputation: 2542
I have an array field on my data. I want to find all documents having a specific two values in that array, and update one of the two. I think I need the $
to do this, but I'm stuck as to how to update the correct element. To make it a little more challenging, the elements of the array are documents, not simple values.
so far I have
db.getCollection('Submissions').update(
{
"data": {$elemMatch:{
label:"Level 2",
value: {$ne: ""}}},
"data": {$elemMatch:{
label:"Level"
}}
},{})
Using find with that query gets me the right document, now I want to update from those the element with label "Level" and set the value to 2. That'sthe bit that stumps me.
Upvotes: 1
Views: 2447
Reputation: 37128
You can't use $
directly. It refers to the first matching sub-document, and you have at least 2 matching ones.
You need to do it on application level. Select document id, then update by id:
db.getCollection('Submissions').find(
{
"data": {$elemMatch:{
label:"Level 2",
value: {$ne: ""}}},
"data": {$elemMatch:{
label:"Level"
}}
},{_id:1});
db.getCollection('Submissions').update(
{
"_id": "_id from previous query",
"data": {$elemMatch:{
label:"Level"
}}
},{ $set: { "data.$.value": 2} })
Alternatively you can shift second match to $where function to leave only one $elemMatch
that should match the sub-document to update:
db.getCollection('Submissions').update(
{
"data": {$elemMatch:{ label:"Level"} },
$where: function() {
return obj.data.filter(
el => el.label == "Level 2" && el.value != ""
).length >= 1
},
},{ $set: { "data.$.value": 2} })
It is quite slow though. I didn't benchmark it, but I believe the first approach should be faster.
Upvotes: 2