4

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 が提供する関数のスコープに関するものですが、なぜそれが呼び出されないのか、エラーがスローされるのかはよくわかりません。

4

2 に答える 2

3

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}
    }
);
于 2012-07-27T11:58:50.370 に答える
0

マッパーの宣言に問題があると思います:

あなたのコード:

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; 

functionステートメントは、すぐに実行したい関数を宣言していますが、実行していません。

そしてitem;、それ自体はまったく問題のない JavaScript です。何もしませんが、有効です。(のように"use strict";)

あなたが欲しいのは関数です:

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

ここで重要な部分はfunction、行頭自体を持たないことです。関数式の()前後は必須ではありませんが、関数をすぐに実行することを示しています。変数に代入しなかった場合は、これらが必要になります。で行を開始しないようにしfunctionます。

于 2012-07-27T12:13:08.337 に答える