Chciałbym wykonać kilka funkcji JavaScript, które wykonują mapę parametryczną / zmniejszają zadania w Mongo, ale jestem zdezorientowany w zakresie scopingu JavaScript. Na przykład poniższy kod daje mi liczenia zmiennej "gender"; tj. Powiem mi, ile "male" i "female" Records:

// 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}}
);

Działa to idealnie dobrze. W następnym kroku chciałbym stworzyć funkcję, która robi to na dowolną własność

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")

Jednak kiedy próbuję:

countCategories("gender")
{
    "results" : [ ],
    "timeMillis" : 48,
    "counts" : {
        "input" : 2462,
        "emit" : 0,
        "reduce" : 0,
        "output" : 0
    },
    "ok" : 1,
}

Funkcja EMIT nigdy nie została wywołana. Co tu poszło nie tak? Domyślam się, że jest czymś z zakresem funkcji {X0}}.

4
Jeroen Ooms 27 lipiec 2012, 15:00

2 odpowiedzi

Najlepsza odpowiedź

Z tego, co czytałem w Dokumenty, zakres funkcji do użycia W poleceniu bazy danych nie jest ich domyślnym zakresem JavaScript, ale może (i musi, w razie potrzeby) być ustawiony ręcznie. Więc myślę, że to powinno pracować:

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

Myślę, że masz problem w Deklaracji Mappera:

Twój kod:

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

Jest równoważne, ze względu na składnia JavaScript Składnia / podnoszenie / Semicolon Insertion, do:

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

item; 

Twoja funkcja oświadczenie deklaruje funkcję, którą chcesz natychmiast wykonać, ale nie.

I item; na to, że jest to idealnie OK JavaScript. Nic nie robi, ale jest ważne. (Jak "use strict";)

Co chcesz, jest funkcją wyrażenie :

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

Ważną częścią tutaj nie ma function na początku linii samodzielnie. () wokół wyrażenia funkcji nie jest wymagane, ale wskazuje, że natychmiast wykonujesz funkcję. Byłyby wymagane, jeśli nie przypisałeś zmiennej; Aby uniknąć uruchomienia linii za pomocą function.

0
Odalrick 27 lipiec 2012, 12:13