2017-10-01 1 views
2

Je veux définir une fonction d'aide pour mon code MapReduce qui peut être paramétré avec une autre fonction (par exemple l'injection de dépendance), similaire à la définition ci-dessous:portée MongoDB MapReduce des fonctions d'ordre supérieur

var helper = function(f) { 
    return function(x) { 
    return f(x); // just an example 
    }; 
} 

Lorsque vous appelez Mongo de MapReduce, je passe la fonction (déjà résolu) dans le cadre:

var options = { 
    scope: { 
    doStuff: helper(someFun) 
    }, 
    … 
}; 

var map = function() { … }; 
var reduce = function(key, values) { doStuff(…); … }; 

db.collection('test').mapReduce(map, reduce, options); 

j'attendre à ce que f contiendra someFun dans la fonction de retour et peut être utilisé sur la carte ou réduire les fonctions. Mais il n'a pas, MapReduce échoue et rapports mongo:

{ MongoError: ReferenceError: f is not defined : …

peut-il être fait? Ai-je besoin de réécrire ma fonction pour que la portée/fermeture soit préservée? Si possible, je voudrais éviter de définir f dans le scope aussi, car je pense que cela va probablement se casser dans le futur (les développeurs oublient d'ajouter toutes les fonctions requises à la portée, etc.)

+0

n'est pas ce que ce mot-clé dans ce Javascript est pour? – Deano

+0

Je suis très heureux de résoudre mon problème en utilisant 'this' de la bonne façon, bien que je pense que ce n'est pas lié à ma question. – knittl

Répondre

0

Voilà comment je faites-le:

// re-useable helpers to generate mongodb map functions 
// (mongoshell-compatible dependency injection) 

// creates a renderDate() function to be used from map() functions 
function renderDate() { 
    var DAY_MS = 1000 * 60 * 60 * 24; 
    var renderDate = t => 
    new Date(DAY_MS * Math.floor(t/DAY_MS)).toISOString().split('T')[0]; 
} 

// generates a map function after injecting code from the mapHelpers() function 
function makeMapWith(mapHelpers, mapTemplate) { 
    const getFuncBody = fct => { 
    var entire = fct.toString(); 
    return entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}")); 
    }; 
    return new Function([ 
    getFuncBody(mapHelpers), 
    getFuncBody(mapTemplate), 
    ].join('\n')); 
} 

const map = makeMapWith(renderDate, function mapTemplate(){ 
    // the body of this map() function can use renderDate 
    // because it's injected by makeMapWith() 
    emit(renderDate(this._id.getTimestamp()), {}); 
}); 

// the map function can safely be passed to mongodb's mapReduce()