Ori Dar
Ori Dar

Reputation: 19000

Merge into a nested object using mongodb aggregation

I have a MongoDB collection with a document structure similar to:

{
    "_id" : "xxx",
    "inner : {
        "foo" : 1,
        "bar" : 2
    }
}

Database version is 4.2.6

and an aggregation pipeline whose penultimate stage is $project with an outcome document matching something like this one:

{
    "_id" : "xxx",
    "inner : {
        "baz" : 3
    }
}

Followed by a final stage to merge into the collection:

{
    "$merge" : {
        into: "myCollection",
        on: "_id",
        whenMatched: "merge",
        whenNotMatched: "discard"
    }
}

However as a result, the existing inner document fields are overridden by the $merge results. Meaning:

Expected results:

{
    "_id" : "xxx",
    "inner : {
        "foo" : 1,
        "bar" : 2,
        "baz" : 3
    }
}

Actual results:

{
    "_id" : "xxx",
    "inner : {
        "baz" : 3
    }
}

How can I overcome this?

Upvotes: 1

Views: 4548

Answers (2)

Ori Dar
Ori Dar

Reputation: 19000

The accepted answer was a good lead, although the $project pipeline caused every field except for _id and inner to be overridden. This is not what I had wanted of course.

What should have been the obvious choice, was simply to use $addFields instead:

 whenMatched:  [
     {"$addFields" :
         {"inner.baz": "$$new.baz"}
     }
 ]

Upvotes: 4

Takis
Takis

Reputation: 8693

The "merge" option merges the root document, so inner field is replaced in your query.
Try to replace the merge with this merge that uses pipeline.
I haven't tested it but i think it will be ok.
$$new variable is mongo-defined to refer to the document coming from pipeline.

{
    "$merge" : {
        into: "myCollection",
        on: "_id",
        whenMatched: 
          [{"$project": 
             {"_id": "$_id",
              "inner": {"$mergeObjects": ["$inner","$$new.inner"]}}}],
        whenNotMatched: "discard"
    }
}

Upvotes: 4

Related Questions