skip to Main Content

I have a nested mongo array

{
  "_id": 1,
  "date": "2024-09-30",
  "employees": [
    {
      "_id": 101,
      "name": "John Doe",
      "company": "ABC Corp",
      "department": "HR",
      "salary": 50000,
      "contactNumber": "123-456-7890"
    },
    {
      "_id": 102,
      "name": "A",
      "company": "XYZ Corp",
      "department": "HR",
      "salary": 500100,
      "contactNumber": "1333-456-7890"
    },
    {
      "_id": 103,
      "name": "B",
      "company": "XYZ Corp",
      "department": "HR",
      "salary": 500100,
      "contactNumber": "1333-456-7890"
    }
  ]
}


I need to update the salary of 101 and also add new memeber 104. How can i do in single update?

I am able to do with 2 updates. One to update 101’s salary using ArrayFilters and another is to $push 104 to array. Below are the queries,

db.collection.updateOne(
  { _id: 1 },  // Match the document with _id: 1
  {
    $set: { "employees.$[emp].salary": 60000 }  // Set the new salary for employee with _id: 101
  },
  {
    arrayFilters: [ { "emp._id": 101 } ]  // Array filter to target the specific employee with _id: 101
  }
)
db.collection.updateOne(
  { _id: 1 },  // Match the document with _id: 1
  {
    $push: {
      employees: {
        _id: 104,
        name: "New Employee",
        company: "New Corp",
        department: "HR",
        salary: 70000,
        contactNumber: "987-654-3210"
      }
    }
  }
)

Is there any way I can do both adding new employee and updating existing employee in same query.?

I think I can use aggregate to do so. but which is better in case of performance?

2

Answers


  1. This can’t be be in a single update query – "Updating the path ’employees’ would create a conflict at ’employees’" – which happens because both operations are on the ’employees’ field. However, if you were pushing to a different field like newEmployees, then it would work. The only difference in those two linked queries is the field for $push.

    Anyway, wrt to doing both together with an aggregation, one agg would be faster than two separate updates but probably not worth the complexity. Does a new employee need to be added every time another employee’s salary changes?

    If you need "both work or both fail" behaviour, then consider using transactions.

    Login or Signup to reply.
  2. You can do the followings in an update with aggregation pipeline.

    1. $concatArrays to append the new 104 entry to the end of the employees array
    2. $map to iterate through the resulting array. Conditionally update the array entry with $mergeObjects if the entry’s id is 101
    db.collection.update({
      "_id": 1
    },
    [
      {
        "$set": {
          "employees": {
            "$map": {
              "input": {
                "$concatArrays": [
                  "$employees",
                  [
                    // new employee to insert here
                    {
                      _id: 104,
                      name: "New Employee",
                      company: "New Corp",
                      department: "HR",
                      salary: 70000,
                      contactNumber: "987-654-3210"
                    }
                  ]
                ]
              },
              "as": "e",
              "in": {
                "$cond": {
                  "if": {
                    "$eq": [
                      101,
                      "$$e._id"
                    ]
                  },
                  "then": {
                    "$mergeObjects": [
                      "$$e",
                      {
                        // updates that you want to perform here
                        "salary": 60000
                      }
                    ]
                  },
                  "else": "$$e"
                }
              }
            }
          }
        }
      }
    ])
    

    Mongo Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search