Reputation: 3821
I'm running a map reduce operation and ending up with bad data. Here are my map and reduce functions:
var map_analytics = function() {
var key = this.owner;
if (this.apikey == null) {
var value = {api_call_with_key: 0, api_call_without_key: 1};
} else {
var value = {api_call_with_key: 1, api_call_without_key: 0};
}
emit(key, value);
};
var reduce_analytics = function(key_owner, api_calls) {
today = new Date();
firstofmonth = new Date(today.getFullYear(), today.getMonth(), 1);
reduced_val = {period: firstofmonth, analytics: {api_call_with_key: 0, api_call_without_key: 0}};
api_calls.forEach(function(value) {
reduced_val.analytics.api_call_with_key += value.api_call_with_key;
reduced_val.analytics.api_call_without_key += value.api_call_without_key;
});
return reduced_val;
};
Now when I run my map reduce:
db.statistics.mapReduce(map_analytics, reduce_analytics, {out: { reduce: "analytics" }, query: { request_date: { $gte: firstofmonth}}})
I get this:
{
"_id" : ObjectId("5136d880136b961c98c9a62f"),
"value" : {
"period" : ISODate("2013-05-01T06:00:00Z"),
"analytics" : {
"api_call_with_key" : NaN,
"api_call_without_key" : NaN
}
}
}
Any idea why I'm getting NaN instead of actual values?
A more simple version of this works:
var reduce_analytics = function(key_owner, api_calls) {
reduced_val = {api_call_with_key: 0, api_call_without_key: 0};
api_calls.forEach(function(value) {
reduced_val.api_call_with_key += value.api_call_with_key;
reduced_val.api_call_without_key += value.api_call_without_key;
});
return reduced_val;
};
And produces
{
"_id" : ObjectId("5143b2c8136b9616343dacec"),
"value" : {
"api_call_with_key" : 0,
"api_call_without_key" : 2,
"total_api_calls" : 2
}
}
How can I output a more complex object?
Upvotes: 1
Views: 1405
Reputation: 40639
Try this:
api_calls.forEach(function(value) {
reduced_val.analytics.api_call_with_key += Number(value.api_call_with_key);
reduced_val.analytics.api_call_without_key += Number(value.api_call_without_key);
});
Upvotes: 0
Reputation: 42352
You cannot change the format of your value between map and reduce.
In other words, when your map emits (key, VALUE) your reduce function MUST return the same format VALUE.
So if you want to have date as part of your value, you need to put it in during the mapping phase. If you are grouping by key, date then it should be part of the key document.
In addition, I would recommend using aggregation framework for this if you can - it's much faster than map-reduce.
Upvotes: 1