views:

61

answers:

3

Hi, 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.

A: 

Considering only the JS part, i'm not sure whether the following part is valid -

values.forEach(function(v){ count += v['count'];});

try this instead -

var v;
for (v in values)
{
    ....
}

hope that helps!

anirvan
that part is valid, because I would get correct results for some reduce operations, and a NaN for others.
Kaustubh P
i only questioned the syntactic validity of that part. i can very well understand what it is meant to do!
anirvan
A: 

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.

Kaustubh P
+2  A: 

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.

Niels van der Rest
thanks a lot, i read it many times, but when you explained it like that, I understood it well.
Kaustubh P