Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB array aggregation

Tags:

mongodb

I have two documents like this

{ "_id" : ObjectId("552cd26276b783ed66031cc4"), "vals" : [  2,  3,  4,  5 ] }
{ "_id" : ObjectId("552cd26e76b783ed66031cc5"), "vals" : [  1,  2,  3,  4 ] }

I need aggregated sum of this two lists

expected output:

[3, 5, 7, 9]

i.e [2+1, 3+2, 4+3, 5+4]

I'm not even sure if this is possible in MongoDB. Any light on this?

like image 321
thavan Avatar asked Apr 14 '15 10:04

thavan


1 Answers

Just for an update. This is possible in aggregation framework in the upcoming release of mongoDB 3.2. They have added a new feature to get the unwind index of array in $unwind stage of mongoDB aggregation called includeArrayIndex.

Using this feature you can use aggregate query of the form:

db.collection.aggregate(
  {$unwind: { path: "$vals", includeArrayIndex: "arrayIndex" }},
  {$group: { '_id': '$arrayIndex', sum : {$sum: '$vals'}}},
  {$sort: { '_id': 1 }},
  {$group : { '_id': null, valSum: {$push: '$sum'}}}
)

Explanation:

  • The unwind operation unwinds the vals array and also projects the array index of unwind. So the idea is to group similar indexes so that we can sum them
  • We then group based on the arrayIndex while summing the vals element. In this stage we have perfectly summed the corresponding index elements
  • Next we sort based on arrayIndex so as to prepare for final result array
  • Next we group all documents and push the sums to an array called valSum

Output:

{ '_id': null, valSum: [3, 5, 7, 9] }

The main advantage of this approach is that, you need not have arrays of same length. Also it can take any number of input documents. Thanks to the includeArrayIndex feature.

Cheers!

like image 53
Sarath Nair Avatar answered Sep 26 '22 02:09

Sarath Nair