MongoDB array aggregation

I have two such documents:

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

I need the aggregated sum of these two lists

expected output:

 [3, 5, 7, 9] 

ie [2 + 1, 3 + 2, 4 + 3, 5 + 4]

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

+7
mongodb
source share
3 answers

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

Using this function, you can use an aggregated form request:

 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 index of the unwind array. Thus, the idea is to group similar indices so that we can summarize them.
  • Then we group based on arrayIndex, adding up the vals element. At this point, we perfectly summarized the corresponding index elements
  • Next, we sort based on arrayIndex to prepare for the final array of results.
  • Then we group all the documents and push the amounts into an array called valSum

Output:

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

The main advantage of this approach is that you do not need to have arrays of the same length. It can also accept any number of input documents. Thanks to the includeArrayIndex function.

Hooray!

+1
source share

Sorry, I did not answer the question correctly. I was thinking about how to sum each array of objects. Do not add arrays between two objects.

(see above)

I'm new to this, but I think you want to use the $ unwind aggregate operator, which will blow up the array, and then $ sum "vals". It should look like this.

 db.Test.aggregate([{$unwind:"$vals"},{$group:{_id:"$_id","TotalVals":{$sum:"$vals"}}}]) 

refer to the operators here http://docs.mongodb.org/manual/reference/operator/aggregation-group/

This ($ unwind) will create one document for each value in the array, so watch your memory for large collections. This ($ unwind) is executed in memory, I suppose.

0
source share

Aggregation structure is not only an aggregation conveyor.

Of course, you can also use map reduction with really simple functions:

 var map_function = function(){ for(var i=0;i<this.vals.length;i++){ emit(i,this.vals[i]); } } var reduce_function = function(key, values){ return Array.sum(values) } 

The output is a list of documents, where _id is the index and value is the sum. Like this:

 [{u'_id': 0.0, u'value': 3.0}, {u'_id': 1.0, u'value': 5.0}, {u'_id': 2.0, u'value': 7.0}, {u'_id': 3.0, u'value': 9.0}] 
0
source share

All Articles