I have a M/R function, and I get NaN as a value for some of the results. I dont have any experience with JS. Im escaping JS using Java Drivers.
String map = "function(){" + " emit({"
+ "country: this.info.location.country, "
+ "industry: this.info.industry}, {count : 1}); }";
String reduce = "function(key, values){var count = 0.0;"
+ "values.forEach(function(v){ count += v['count'];});"
+ "return count;}";
MapReduceOutput output = collection.mapReduce(map, reduce, null,
new BasicDBObject("lid", "foo"));
An example ti help clear things:
{"_id":{"country":"gb", "industry":"foo"}, "value":NaN}
Thanks a lot.
I see you have solved the problem, but here's why the problem occurred.
MongoDB may rerun your reduce function on the results of previous reduce passes. This is called a re-reduce.
If a re-reduce occurred in your original scenario, you could end up with values like this:
[
{ count: 1 },
{ count: 1 },
4
{ count: 1 },
{ count: 1 },
{ count: 1 },
3
{ count: 1 },
]
All the { count: 1 }
values are emitted by your map function. The numbers 4
and 3
are the results of previous reduce calls. Your reduce function will then access the count
property of a number:
count += 4["count"];
A number doesn't have a count
property, so it will return undefined
. Adding undefined
to a number will result in NaN
.
To avoid this kind of hard-to-debug problem, you need to make sure your reduce function is idempotent. The easiest way to accomplish this is to return what you emit; the value you return in the reduce function should be of the same format as the values you emit in the map function.
I solved it. Changed the loop, as anirvan said. But still I got a NaN. So i changed the return statement as such:
for(var i in values) { count += values[i].count; } return {count: count}; }
That did the trick. Ill need an extra line to parse it, but IDC.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With