Search code examples
arraysmongodbmongodb-querymongodb-update

Update nested array object value by replacing substring of that object property


I have the following set of data in my MongoDB collection called orders:

{
    "_id" : ObjectId("618e0e1b17687316dcdd6246"),
    "groupUID": "abc",
    "orderData" : {
        "charges" : {
            "total" : 18480.0,
            "subtotal" : 13980.0 
        },
        "items" : [ 
            {
                "name" : "Chocolate cookies",
                "imageURL": "domainURL2.com/cookies"
            },
            {
                "name" : "Chocolate muffins",
                "imageURL": "domainURL2.com/muffins"
            }
        ]
    }
}

Now I want to update the imageURL substring part of "domainURL2" to "domainURL1" field in every document of this collection. I have the following query so far:

db.orders.update(
    {
        "groupUID" : "abc"
    },
    { "$set": { "orderData.items.$.imageURL":"myURL.com" } } )

I also have the query in JavaScript form but I want this to be in pure Mongo query. So the query below will not do it for me unfortunately.

db.getCollection("orders").find({"groupUID" : "abc"}).forEach(function(aRow) {
    if (aRow.orderDetails !== undefined) {
    var updated = false;
        aRow.orderData.items.forEach(function(item) {

item.imageURL = item.imageURL.replace("eddress/", "noknok-app/");
        })
db.getCollection("orders").save(aRow);
    }
});

I want to update all records' imageURL field's substring part. I am unable to figure out the rest of the query. Can anyone please help me?


Solution

  • My answer may look complex (Welcome for suggestion/improvement).

    Work the update with Aggegration Pipeline.

    1. $set - Update orderData.items field.

      1.1. $map - Iterate orderData.items and returns new array.

      1.1.1. $mergeObjects - Merge current object and imageURL field from 1.1.1.1.

      1.1.1.1. $cond - With $regexMatch to find the imageURL starts with "domainURL2.com".

      1.1.1.2. If true, then replace "domainURL2.com" with "domainURL1.com".

      1.1.1.3. If false, remain existing value.

    db.collection.update({
      "groupUID": "abc"
    },
    [
      {
        "$set": {
          "orderData.items": {
            $map: {
              input: "$orderData.items",
              in: {
                $mergeObjects: [
                  "$$this",
                  {
                    imageURL: {
                      $cond: {
                        if: {
                          $regexMatch: {
                            input: "$$this.imageURL",
                            regex: "^domainURL2.com"
                          }
                        },
                        then: {
                          $concat: [
                            "domainURL1.com",
                            {
                              $arrayElemAt: [
                                {
                                  $split: [
                                    "$$this.imageURL",
                                    "domainURL2.com"
                                  ]
                                },
                                -1
                              ]
                            }
                          ]
                        },
                        else: "$$this.imageURL"
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    Sample Mongo Playground


    Another approach is using $replaceOne (suggested by @rickhg12hs) which will be much easier.

    $replaceOne to replace for 1.1.1.1.

    db.collection.update({
      "groupUID": "abc"
    },
    [
      {
        "$set": {
          "orderData.items": {
            $map: {
              input: "$orderData.items",
              in: {
                $mergeObjects: [
                  "$$this",
                  {
                    imageURL: {
                      $replaceOne: {
                        input: "$$this.imageURL",
                        find: "domainURL2.com",
                        replacement: "domainURL1.com"
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ])
    

    Sample Mongo Playground ($replaceOne)