This is a question about the best way to add up a series of data in an array where I have to match another element. I\'m trying to use the 2.2 Aggregation framework and it\'
You can use the aggregation framework to get sales and profit and any other value you may be storing in your key/value pair representation.
For your example data:
var pipeline = [
{
"$unwind" : "$finance"
},
{
"$group" : {
"_id" : "$finance.k",
"numberOf" : {
"$sum" : 1
},
"total" : {
"$sum" : "$finance.v.v"
}
}
}
]
R = db.tb.aggregate( pipeline );
printjson(R);
{
"result" : [
{
"_id" : "profit",
"numberOf" : 2,
"total" : 246246
},
{
"_id" : "sales",
"numberOf" : 2,
"total" : 468000
}
],
"ok" : 1
}
If you have additional k/v pairs then you can add a match which only passes through k values in ["sales","profit"].
You will have to use '$unwind" to break out the values in the array, which will mean that you can't get the sum of the sales and the profit in a single aggregation command. Given that, the query itself is easy:
var pipeline = [
{"$unwind": "$finance" } ,
{"$match": {"finance.k": "sales"} },
{ $group:
{ _id: null,
numberOf: { "$sum": 1 },
sales: {"$sum": "$finance.v.v" }
}
}
];
R = db.tb.aggregate( pipeline );
printjson(R);
{
"result" : [
{
"_id" : null,
"numberOf" : 2,
"sales" : 236340
}
],
"ok" : 1
}
You can run a similar query for profit, just substitute "profit" for "sales" in the "$match" operator.
Oh, and here's the map/reduce example:
map = function() {
var ret = { sales: 0.0 , profit: 0.0, count: 1 };
// iterate over 'finance[]' array
this.finance.forEach( function (i) {
if ( i.k == "sales" ) ret.sales = i.v.v ;
if ( i.k == "profit" ) ret.profit = i.v.v ;
} );
emit( 1, ret );
}
reduce = function(key, values) {
var ret = { sales: 0.0 , profit: 0.0, count: 0 };
values.forEach(function(v) {
ret.sales += v.sales;
ret.profit += v.profit;
ret.count += v.count;
});
return ret;
};
//
// run map/reduce
//
res = SOURCE.mapReduce( map, reduce );