我想制作一些在mongo中执行参数化map / reduce作业的javascript函数,但我对JavaScript的范围设置感到困惑.例如,以下代码给出了“性别”变量的计数;即它会告诉我有多少“男性”和“女性”记录:
// 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}}
);
这完全没问题.在下一步中,我想创建一个为任意属性执行此操作的函数
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")
但是,当我尝试:
countCategories("gender")
{
"results" : [ ],
"timeMillis" : 48,
"counts" : {
"input" : 2462,
"emit" : 0,
"reduce" : 0,
"output" : 0
},
"ok" : 1,
}
从未调用emit函数.这里出了什么问题?我的猜测是mongo提供的emit函数的范围,但我不确定为什么它没有被调用,也没有抛出错误.
解决方法:
从我在the docs中读到的内容,数据库命令中使用的函数范围不是它们的默认javascript范围,但可以(并且必须,如果需要)手动设置.所以,它认为这应该工作:
var mapper = function(){
if(item in this){
emit(this[item], {count: 1});
}
};
...
db.responses.mapReduce(
mapper,
reducer,
{
out: {"inline": 1},
scope: {"item": item}
}
);