skip to Main Content

Need mongodb query : if I get a order , vendorID in input params that already exists with specific orderNumber I need to update it in orders array by replacing the whole existing order element with that orderNumber with newly provided order in input params, else insert it

Suppose input param has three attributes :

  1. orderNumber : "order2"
  2. order: {"orderNumber":"order2", "data":"NEW_DATA_FROM_INPUT" }
  3. vendorId : "vendor1"

Here is the sample data in DB:

{
  "_id":1,
  "vendorId":"Vendor1",
  "orders":[
    {
      "orderNumber":"order1",
      "data":"data1"
    },
    {
      "orderNumber":"order2",
      "data":"data2"
    }
  ]
}

THE QUERY SHOULD UPDATE THE RECORD AS BELOW:

{
  "_id":1,
  "vendorId":"Vendor1",
  "orders":[
    {
      "orderNumber":"order1",
      "data":"data1"
    },
    {
      "orderNumber":"order2",
      "data":"NEW_DATA_FROM_INPUT"  // !!
    }
  ]
}

Tried $set, $addtoSet but they cannot be used together on same path due to mongo limitations.

2

Answers


  1. One way to do it is to use an aggregation pipeline in the update.

    N.B.: Comments in update listing below. Depending on the app/driver you are using, you may need to change db.collection.update to something else (and you probably don’t want/need {"multi": true}).

    db.collection.update({
      // find doc with correct "vendorId"
      "vendorId": "Vendor1"
    },
    // use pipeline
    [{
      // rebuild "orders"
      "$set": {
        "orders": {
          "$let": {
            "vars": {
              // from input params
              "orderParam": {
                "orderNumber": "order2",
                "data": "NEW_DATA_FROM_INPUT"
              }
            },
            "in": {
              "$cond": [
                // does "orders.orderNumber" exist and is array?
                {
                  "$eq": [{"$type": "$orders.orderNumber"}, "array"]
                },
                // yes, "orders.orderNumber" exists and is array
                {
                  "$cond": [
                    // does an order need rewriten "data"?
                    {
                      "$in": ["order2", "$orders.orderNumber"]
                    },
                    // yes, rewrite specific order, keep the rest
                    {
                      "$map": {
                        "input": "$orders",
                        "as": "order",
                        "in": {
                          "$cond": [
                            // is this the order?
                            {
                              "$eq": ["$$order.orderNumber", "$$orderParam.orderNumber"]
                            },
                            // yes, rewrite this order
                            {
                              "$mergeObjects": [
                                "$$order",
                                {"data": "$$orderParam.data"}
                              ]
                            },
                            // not the order, so keep it
                            "$$order"
                          ]
                        }
                      }
                    },
                    // no, order is not there, so just append it
                    {
                      "$concatArrays": ["$orders", ["$$orderParam"]]
                    }
                  ]
                },
                // nobody home, create it
                ["$$orderParam"]
              ]
            }
          }
        }
      }
    }
    ],
    {
      "multi": true
    })
    

    Try it on mongoplayground.net where you will see various test cases.

    Login or Signup to reply.
  2. In case of updation, we can use positional operation "$" with updateOne() or updateMany() which helps in updating the first occurrence to be updated with the provided values.

    For eg. In the above case we need to update the 2nd index object value.

    db.collection.updateOne({_id:1,"orders.orderNumber":"order2"},{$set:{ "orders.$.data": "NEW_DATA_FROM_INPUT" }});
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search