Javascript scoping rules and mongo map/reduce functions

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:

var mapper = function(){
    if(item in this){
        emit(this[item], {count: 1});
    }
};
...
db.responses.mapReduce(
    mapper, 
    reducer, 
    {
       out: {"inline": 1},
       scope: {"item": item}
    }
);

I think you have a problem in the declaration of mapper:

Your code:

function mapper(it){
    fn = function(){
        if(this[it]){
            emit(this[it], {count: 1});
        }
    };
    return fn;
}(item); 

Is equivalent, due to the JavaScript syntax/hoisting/semicolon insertion stuff, to:

function mapper(it){
    fn = function(){
        if(this[it]){
            emit(this[it], {count: 1});
        }
    };
    return fn;
}

item; 

Your function statement declares a function that you want to execute immediately, but you don't.

And item; on it's own like that is perfectly ok JavaScript. It doesn't do anything, but it's valid. (Like "use strict";)

What you want is a function expression :

var mapper = (function (it){
    fn = function(){
        if(this[it]){
            emit(this[it], {count: 1});
        }
    };
    return fn;
})(item); 

The important part here is not having function at the start of line by itself. The () around the function expression aren't required, but it indicates that you execute the function immediately. They would be required if you didn't assign to a variable; to avoid starting a line with function.