MongoDB MapReduce范围更高阶函数

时间:2017-10-01 12:12:58

标签: javascript mongodb scope mapreduce

我想为mapreduce代码定义一个辅助函数,可以用另一个函数(即依赖注入)进行参数化,类似于下面的定义:

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

当调用Mongo的mapreduce时,我在范围内传递(已经解析的)函数:

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

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

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

我希望f在返回的函数中包含someFun,并且可以在map或reduce函数中使用。但事实并非如此,mapreduce失败了,Mongo报道:

  

{ MongoError: ReferenceError: f is not defined : …

可以这样做吗?我是否需要重写我的函数以保留范围/闭包?如果可能的话,我也希望避免在范围中定义f,因为我觉得这可能会在将来中断(开发人员忘记将所有必需的功能添加到范围等)。

1 个答案:

答案 0 :(得分:0)

我就是这样做的:

// 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()