bssyy78
bssyy78

Reputation: 349

mongo : update property of specific element in array

I have this collection :

{
    "_id" : ObjectId("5ac69e90a9d1a5f3e01a5233"),
    "category": "spain",
    "products" : [ 
        {
            "label" : "uno"
        }, 
        {
            "label" : "dos"
        }, 
        {
            "label" : "tres"
        }
    ]
},
{
    "_id" : ObjectId("5ac69e90a9d1a5f3e01a5234"),
    "category": "england",
    "products" : [ 
        {
            "label" : "one"
        }, 
        {
            "label" : "two"
        }, 
        {
            "label" : "three"
        }
    ]
}

I want to do the following operation : update the label from "one" to "four" of the object with the category england. But I have some troubles to design the most elegant and performant solution :

first solution : I could copy paste and rewrite the entire document with just replacing the one by four second solution where I struggle : I would like to find the element with label equals to one and updates it to four, but I don't know how to do. I don't want to use mongo path index like 'products.O.label' because I can't garantee that the product with label one will be at position 0 in the products array.

Thanks in advance

Upvotes: 1

Views: 60

Answers (2)

Wernfried Domscheit
Wernfried Domscheit

Reputation: 59456

You could use this one:

db.collection.updateMany(
   { category: "england" },
   { $set: { "products.$[element].label": "four" } },
   { arrayFilters: [{ "element.label": "one" }] }
)

If you prefer and aggregation pipeline it would be this one:

db.collection.updateMany(
   { category: "england" },
   [{
      $set: {
         products: {
            $map: {
               input: "$products",
               in: {
                  $cond: {
                     if: { $eq: ["$$this.label", "one"] },
                     then: { label: "four" },
                     else: "$$this"
                  }
               }
            }
         }
      }
   }]
)

but it might be an overkill, in my opinion.

Upvotes: 2

Mallik
Mallik

Reputation: 334

Further, referring to @Wernfried Domscheit, another way using aggregation.

> db.catg1.find();
{ "_id" : ObjectId("5ac69e90a9d1a5f3e01a5233"), "category" : "spain", "products" : [ { "label" : "uno" }, { "label" : "dos" }, { "label" : "tres" } ] }
{ "_id" : ObjectId("5ac69e90a9d1a5f3e01a5234"), "category" : "england", "products" : [ { "label" : "four" }, { "label" : "two two" }, { "label" : "three" } ] }
> db.catg1.aggregate([
... {$unwind:"$products"},
... {$match:{category:"england",
...          "products.label":"four"
...     }
... },
... ]).forEach(function(doc){
...     print(doc._id);
...     db.catg1.update(
...       {"_id":doc._id},
...       { $set:{"products.$[element].label":"one"}},
...       {arrayFilters: [{"element.label":"four"}]}
...   );
... });
ObjectId("5ac69e90a9d1a5f3e01a5234")
> db.catg1.find();
{ "_id" : ObjectId("5ac69e90a9d1a5f3e01a5233"), "category" : "spain", "products" : [ { "label" : "uno" }, { "label" : "dos" }, { "label" : "tres" } ] }
{ "_id" : ObjectId("5ac69e90a9d1a5f3e01a5234"), "category" : "england", "products" : [ { "label" : "one" }, { "label" : "two two" }, { "label" : "three" } ] }
> db.version();
4.2.6
>

Upvotes: 0

Related Questions