I would like to make some javascript functions that perform parametric map/reduce jobs in mongo, but I’m getting confused about the scoping of JavaScript. For example, the following code gives me counts of the "gender" variable; i.e. it will tell me how many "male" and "female" records I have:
// count categories
db.responses.mapReduce(
function(){
emit(this["gender"], {count: 1})
}, function(state, values){
var result = {count: 0};
values.forEach(function(value) {
result.count += value.count;
});
return result;
}, {out: { inline : 1}}
);
This works perfectly fine. In the next step I would like to create a function that does this for an arbitrary property
function countCategories(item) {
function mapper(it){
fn = function(){
if(this[it]){
emit(this[it], {count: 1});
}
};
return fn;
}(item);
var reducer = function(state, values){
var result = {count: 0};
values.forEach(function(value) {
result.count += value.count;
});
return result;
};
var out = {out: { inline : 1}};
var results = db.responses.mapReduce(
mapper,
reducer,
out
);
return results;
}
countCategories("gender")
However when I try:
countCategories("gender")
{
"results" : [ ],
"timeMillis" : 48,
"counts" : {
"input" : 2462,
"emit" : 0,
"reduce" : 0,
"output" : 0
},
"ok" : 1,
}
The emit function has never been called. What has gone wrong here? My guess is something with the scoping of the emit function that mongo supplies, but I’m not quite sure why it is not being called, nor throwing an error.
From what I read in the docs, the scope of functions to be used in database command is not their default javascript scope, but can (and must, if needed) be set manually. So, it think this should work: