$mergeObjects is overwriting object data in update pipeline

When using $mergeObject in update pipeline, the original object is being
overwritten. Are there any alternatives to avoid this from happening or can $mergeObjects be used in any way to avoid this.

I have a document as follows:

{
    "employment": {
      "selfEmployed": {
          "netProfit": 1000,
          "addbacks": [
              {
                "addbackId": "5a934e000102030405000001",
                "value": 1000,
              }
            ]
      }
    }
}

I have update data as follows:

const update = {
    "selfEmployed": {
        "netProfit": 22,
    }
  };

The update query is:

db.collection.update({},
[
  {
    $set: {
      "employment": {
        $mergeObjects: [
          "$employment",
          update
        ]
      }
    }
  }
])

However $mergeObjects overwrites the object to give following result:

  {
    "employment": {
      "selfEmployed": {
        "netProfit": 22
      }
    }
  }

Expected Result:

{
    "employment": {
      "selfEmployed": {
          "netProfit": 22,
          "addbacks": [
              {
                "addbackId": "5a934e000102030405000001",
                "value": 1000,
              }
            ]
      }
    }
}

Playground

Maybe I didn’t get what you want, wouldn’t this be enough:

db.collection.update({},
{
  $set: {
    "employment.selfEmployed.netProfit": 20
  }
})
2 Likes

Yes this will work. But I have a large document and setting like this was not feasible. That’s why I am trying to use update pipeline. And the update will not always have only one key-value.

There is also this option, with a similar code:

db.collection.update({},
[
  {
    $set: {
      "employment.selfEmployed": {
        $mergeObjects: [
          "$employment.selfEmployed",
          {
            "netProfit": 2000
          }
        ]
      }
    }
  }
])

Yet there are probably better options, I was just confused by the question :slight_smile:

3 Likes

Yes this wll work as well. But employment has many other fields other than selfEmployed and handling all those cases like this might be a hassle.

1 Like

This back and forth discussion with correct solutions provided by @santimir is due to the fact that you do not publish real and complete samples of input documents and desired resulting documents.

You keep bringing new facts which make it difficult to provide a complete working solutions.

This looks like your other thread that ended up abruptly from your lack of response.

2 Likes

How to you determine the

that needs to be updated?

No need to bring up my past threads @steevej :grinning:

So I have found somewhat of a solution to my problem(which might be close to what @santiago_miranda1 gave):

db.collection.updateOne({...filter},
[
  {
    $set: {
      "employment": {
        $mergeObjects: [
          "$employment",
          {
            "selfEmployed": {
              $mergeObjects: [
                "$employment.selfEmployed",
                {
                  "netProfitx": 22
                }
              ]
            }
          }
        ]
      }
    }
  }
])

This somewhat works for me right now as I am injecting the second part of first $mergeObjects as per data needs to make a sort of prepared query. As I was needing the top level $set to begin from employment (Sorry about unclear question) I can probably make go with the shown method! Thanks for the interest!

And this query gives the data I want perfectly!

{
    "_id": ObjectId("5a934e000102030405000000"),
    "employment": {
      "selfEmployed": {
        "addbacks": [
          {
            "addbackId": "5a934e000102030405000001",
            "value": 1000
          }
        ],
        "netProfit": 22
      }
    }
  }

Playground

2 Likes

Nice, but I do not understand how you handle the

better than the solution previously provided.

Nested fields like selfEmployed occur less. So I can use the query I originally mentioned and based on some conditions if I need to do nested merge, I can inject some separate logic as second $mergeObjects parameter.

But If i go the way as mentioned by @santiago_miranda1 I will need to write a new query. If I go the way I mentioned I can just extend the already existing query(which might be and some are part of larger queries).

However I will agree that what I answered is not the best solution! I’ll be looking for better soultions!

I can’t read the query, but I’m glad it solved!

It looks like $mergeObjects may be needed several times if we generalize the problem, but it’s good enough if it solves your use case.

There was a similar question in SO. Nothing too useful though.

2 Likes

Thanks for SO link.

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