Perform multiple updates (upserts) on Embedded documents

Hello : )

The above query was not just a array update,it was to change the data the way you said you want them.In the last query you sended you use $push operator,inside an aggregation and you
cant do that.You cant mix aggregation operators/query operators/update operators.

Exception is that you can use aggregate operators to query with $expr.

You can do array update.The bellow does

  1. filter to check if friend already existed based on frined._id(if filter result is empty=> its new friend)
  2. if not existed(not update) adds in the end of the array
  3. if it existed, with $map,$mergeObjects the old friend data with the new friend data
    (no need to do merge you can do replace,or any operation you want)

Data in

{
  "_id": "1",
  "lastName": "Cary",
  "firstName": "paul",
  "dob": "2012-12-12",
  "friends": [
    {
      "_id": "friend_1",
      "lastName": "Eric"
    },
    {
      "_id": "friend_3",
      "lastName": "Charan"
    }
  ]
}

New friend (new friend will be like a variable in your driver)

{"_id" : "friend_1", "lastName" : "Don"}   //this will do update
OR
{"_id" : "friend_10", "lastName" : "Don"}  //this will do add in the end of array

Query(its a command, u= the filter,u= the update(here its pipeline update))
The query is written with newFriend={"_id" : “friend_1”, “lastName” : “Don”}
In the bellow query replace it with the newFriend variable,also where you
see “friend_1” replace it with newFriend.get("_id")

{
  "update": "testcoll",
  "updates": [
    {
      "q": {
        "$expr": {
          "$eq": [
            "$_id",
            "1"
          ]
        }
      },
      "u": [
        {
          "$addFields": {
            "friends": {
              "$let": {
                "vars": {
                  "isNew": {
                    "$eq": [
                      {
                        "$size": {
                          "$filter": {
                            "input": "$friends",
                            "as": "friend",
                            "cond": {
                              "$eq": [
                                "$$friend._id",
                                "friend_1"
                              ]
                            }
                          }
                        }
                      },
                      0
                    ]
                  }
                },
                "in": {
                  "$cond": [
                    "$$isNew",
                    {
                      "$concatArrays": [
                        "$friends",
                        [
                          {
                            "_id": "friend_1",
                            "lastName": "Don"
                          }
                        ]
                      ]
                    },
                    {
                      "$map": {
                        "input": "$friends",
                        "as": "friend",
                        "in": {
                          "$cond": [
                            {
                              "$eq": [
                                "$$friend._id",
                                "friend_1"
                              ]
                            },
                            {
                              "$mergeObjects": [
                                "$$friend",
                                {
                                  "_id": "friend_1",
                                  "lastName": "Don"
                                }
                              ]
                            },
                            "$$friend"
                          ]
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      ],
      "multi": true
    }
  ]
}

Results-before-update
Screenshot from 2021-07-29 19-12-33

After-update-existing-friend
Screenshot from 2021-07-29 19-14-00

After-update-not-existing-friend
Screenshot from 2021-07-29 19-15-14

There are alternative solutions,the simpler solution is to use $reduce,and dont do any checks,
it can be done with 1 array read,but the problem is that we use $concat which is slow if we
do too many of them like >500.(we dont have $push aggregator operator to add in arrays,we have it only as accumulator)

There is also another more complicated solution for big arrays,but here is not needed.
The only cost is that we read the array 2 times instead of 1.