How to use an existing field value with $push in MongoDb?

I have the following Mongo collection,

{
      "_id": ObjectId("5524d12d2702a21830bdb8e5"),
      "code": "Apple",
      "name": "iPhone",
      "parameters": [
        {
          "code": "xxx",
          "name": "Andrew",
          "value": "9",
          
        },
        {
          "code": "yyy",
          "name": "Joy",
          "value": "7",
          
        },
        
      ]
    }

I am using the following query to push into the parameters array object,

db.coll.update({
  "parameters.name": "Andrew"
},
{
  $push: {
    "parameters": {
      "code": "$code",
      "name": "bar",
      "value": "10",
      
    }
  }
},
{
  multi: true
})

However, for the value of code, I want to use the value of the object that matched (i.e. the object with parameters.name == "Andrew", which here is xxx.

Here’s a playground link to the problem Mongo playground Also, I am using a really old version (3.2) of MongoDb. It would be preferable if the solution worked with that. However, if that’s impossible, you can also suggest a solution with the minimum version that’s required.

Hello @Manak_Bisht, Welcome to the MongoDB community forum,

You have to do 2 queries in the 3.2 version, first, find the matching documents, and second, update query (you need to pass that property value from the above first query result).

You can try something like below example, i have not tested,

  • find the documents and use $ projection to return matching element from array
  • prepare the bulk update array for bulkWrite() method
// FIND THE DOCUMENTS
var docs = db.coll.find(
  { "parameters.name": "Andrew" }, 
  { "parameters.$": 1 }
);

// PREPARE THE BULK WRITE OBJECTS
var bulkUpdate = [];
docs.forEach(function(doc) {
  bulkUpdate.push({
    "updateOne": {
      "filter": { "_id" : doc._id },
      "update": { 
        "$push": { 
          "code": doc.parameters[0].code,
          "name": "bar",
          "value": "10"
        } 
      }
    }
  });
});

// BULK WRITE QUERY
db.coll.bulkWrite(bulkUpdate);

Second option,
You can use update with aggregation pipeline starting from v4.2, something like,

  • $concatArrays to concat the existing array with a new object there you can pass code internal property as you tried in your query
  • $indexOfArray to find the array index of matching name
  • $arrayElemAt to find the code of the above matching index
db.coll.updateMany(
  { "parameters.name": "Andrew" },
  [{
    "$set": {
      "parameters": {
        "$concatArrays": [
          "$parameters",
          [
            {
              "code": {
                "$arrayElemAt": [
                  "$parameters.code",
                  { "$indexOfArray": ["$parameters.name", "Andrew"] }
                ]
              },
              "name": "bar",
              "value": "10"
            }
          ]
        ]
      }
    }
  }]
)

Playground

Note: db.collection.update method is deprecated in mongosh. For alternative methods, you can use updateOne for single document updates and updateMany for multiple documents update, see Compatibility Changes with Legacy mongo Shell..

3 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.