9

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?

4
  • is your vals array of same size always ? Commented Apr 14, 2015 at 10:16
  • @yogesh No. But I would like to know if it is possible to solve if the size is same. Commented Apr 14, 2015 at 10:19
  • I think this will not possible using mongo query. And +1 from my side. Commented Apr 14, 2015 at 10:27
  • I agree I don't think this is possible in MongoDB with arbitrary length lists. The issue is that there's no operator to process the lists together directly and, if you unwind one or both arrays, there's no way to appropriately pair up the elements so that you sum the ith element with the ith element and no other pairs. Commented Apr 14, 2015 at 15:26

3 Answers 3

2

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!

Sign up to request clarification or add additional context in comments.

Comments

0

Sorry I didn't answer the question correctly. I was thinking of how to sum each object's array. Not adding the arrays between the two objects.

(edit above)

I am new to this but I think you want to use the aggregate operator $unwind, which will explode the array then $sum the "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 bigger collections. This ($unwind) is done in Memory I believe.

Comments

-1

Aggregation framework is not just the aggregation pipeline.

Of course you can also use map reduce 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 the _id is the index and the 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}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.