4
votes

In a pipeline stage of aggregation I want to call mergeObjects adding the fields instead of replacing.

In the pipeline stage my documents look like this:

{[
  {_id: 'A', fruits: {banana: 2, apple: 1}},
  {_id: 'A', fruits: {banana: 1, pineapple: 3},
  {_id: 'A', fruits: {melon: 1, pineapple: 3, guava: 2}
]}

I want to group all this documents by _id (and the _id of all the documents is always going to be the same), and have the following document as result:

{
  _id: 'A',
  fruits: {banana: 3, apple: 1, pineapple: 6, melon: 1, guava: 2},
}

I'm trying to achieve this by using mergeObjects, but that just replaces the value of a repeated item with the last found in the array and I end up with something like this:

{
  _id: 'A',
  fruits: {banana: 1, apple: 1, pineapple: 3, melon: 1, guava: 2}
}
1

1 Answers

4
votes

You can convert objects to arrays, unwind, group by fields, and convert back to objects:

[
... previous stages ...,

{ $addFields: {
    fruit: {$objectToArray: "$fruits"} 
} },
{ $unwind: "$fruit"},
{ $group: {
    _id: {
        id: "$_id",
        k: "$fruit.k"
    },
    v: {$sum: "$fruit.v"}
} },
{ $group: {
    _id: "$_id.id",
    fruits: { $push: {k: "$_id.k", v: "$v"}}
} },
{ $project: {
    fruits: {$arrayToObject: "$fruits"}
} }
]