【问题标题】:Javascript scoping rules and mongo map/reduce functionsJavascript 范围规则和 mongo map/reduce 函数
【发布时间】:2012-07-26 01:16:04
【问题描述】:

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

【问题讨论】:

  • 你根本不需要闭包,item 已经在countCategories的范围内定义了。为什么不直接将fn 分配给mapper
  • 因为没用...顺便把问题改了一下。
  • 当然,这不是一个解决方案...

标签: javascript node.js mongodb closures mongoose


【解决方案1】:

根据我在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}
    }
);

【讨论】:

    【解决方案2】:

    我觉得你的mapper声明有问题:

    您的代码:

    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 本身不在行首。函数表达式周围的() 不是必需的,但它表示您立即执行该函数。如果您没有分配给变量,则它们将是必需的;避免以function 开头。

    【讨论】:

    • had this before - 不起作用。
    • @Bergi 好吧,至少这解释了为什么您没有收到任何错误。许多内部函数 fn 被创建并被丢弃,却从未被调用过。
    • 我认为这里的根本问题是 mongo 弄乱了函数的环境,以某种方式将 emit() 函数注入它的范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    相关资源
    最近更新 更多