Javascript作用域规则和mongo-map/reduce函数

Javascript scoping rules and mongo map/reduce functions

本文关键字:reduce 函数 mongo-map 作用域 规则 Javascript      更新时间:2024-04-23

我想制作一些在mongo中执行参数映射/减少作业的javascript函数,但我对javascript的作用域感到困惑。例如,下面的代码给出了"gender"变量的计数;即它会告诉我我有多少"male""female"记录:

// 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函数的作用域,但我不太确定为什么它没有被调用,也没有抛出错误。

根据我在文档中所读到的内容,数据库命令中要使用的函数范围不是它们默认的javascript范围,而是可以(如果需要,也必须)手动设置的。因此,它认为这应该起作用:

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

我认为您在映射程序的声明中有问题:

您的代码:

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

由于JavaScript语法/提升/分号插入的东西,相当于:

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

函数语句声明了一个要立即执行的函数,但您没有。

item;本身就是一个很好的JavaScript。它没有任何作用,但它是有效的。(类似"use strict";

您想要的是函数表达式:

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

这里的重要部分是function本身不在行的开头。函数表达式周围的()不是必需的,但它表示您立即执行函数。如果你没有分配给一个变量,它们将是必需的;以避免以CCD_ 9开始一行。