Bishwarup Das
Bishwarup Das

Reputation: 731

MongoDB update Query in a loop

I am working with MongoDB in one of my project. For the next feature I need to add a flag to array of objects by looping with a matching condition.

Following is an example of document that I have -

{
    "_id" : ObjectId("5aaa4eb211a1c1c1f74c1657"),
    "colors" : [
       { "status" : "done" },
       { "status" : "done" },
       { "status" : "n/a" }
   ]        
}

Output should be -

{
   "_id" : ObjectId("5aaa4eb211a1c1c1f74c1657"),
   "colors" : [
       {
           "status" : "done",
           "is_in_production" : true
       }, 
       {
           "status" : "done",
           "is_in_production" : true
       },
       {
        "status" : "n/a"
       }
   ]
}

I used the following query -

db.getCollection('products').update( 
   {
       "colors.status": {
          "$in":[
             "done"
          ]
       }
   },
   {$set: { 'colors.$[].is_in_production' :true }},
   {multi: true}
)

That resulted the following error -

cannot use the part(colors of colors.$[].is_in_production)totraversetheelement({ colors: [{ "status" : "done" }, { "status" : "done" }, { "status" : "n/a" }] )}

Can someone help me with the query?? Thanks in Advance

Upvotes: 3

Views: 7122

Answers (2)

Clement Amarnath
Clement Amarnath

Reputation: 5476

Use updateMany together with arrayFilters to update multiple documents in an array

db.products.updateMany(
   { "colors.status": "done" },
   { $set: { "colors.$[element].is_in_production" : true}},
   { arrayFilters: [{"element.status" : "done"}]}
)

Upvotes: 2

Rahul Raj
Rahul Raj

Reputation: 3459

Use arrayFilters to update only a subset of embedded documents.

Try this query:

db.products.update(
{
   "colors.status": {
      "$in":[
         "done"
        ]
     }
  },
  {$set: { 'colors.$[element].is_in_production' :true }},
  {multi: true, arrayFilters:[{"element.status":"done"}]}
)

Output is:

/* 1 */
{
"_id" : ObjectId("5aaa4eb211a1c1c1f74c1657"),
"colors" : [ 
    {
        "status" : "done",
        "is_in_production" : true
    }, 
    {
        "status" : "done",
        "is_in_production" : true
    }, 
    {
        "status" : "n/a"
    }
  ]
}

enter image description here

Note that you need MongoDB 3.6 and need to execute on latest shell (no third party tools preferably) in order for the arrayFilters to work properly.

If the above query isn't working for your Mongo version, try this query:

db.sample.findAndModify({
  query:{
     "colors.status": {
        "$in":[
           "done"
        ]
     }
 },
 update:{$set: { 'colors.$[element].is_in_production' : true }},
 multi: true, 
 arrayFilters:[{"element.status":"done"}]
})

Upvotes: 1

Related Questions