从sails.js/mongodb中提取公共代码

Extract common code from sails.js / mongodb

本文关键字:提取 代码 mongodb sails js      更新时间:2023-09-26

我目前正在尝试将sails.js与mongodb一起使用,我需要一些自定义的mapReduce函数来对数据进行分组。

现在我可以通过使用水线的native函数来实现我想要的,但有一些问题。

实际上,这些函数只有很小的变化,但我发现自己一直在重复以下代码:

function getSomeData() {
  // First-query
  Log.native(function(err, logCollection) {
    var mapFunction = function() {
      function dateFormatter(date) {
        return date.getFullYear() + "-" + (date.getMonth() + 1)
      }
      //! Generate Grouping Key
      emit(dateFormatter(this.emb_date), this.bad_qty)
    }
    var reduceFunction = function (key, values) {
      return Array.sum(values);
    }
    var outputControl = {
      out: {inline: 1},
      //! Filters
      query: {order_type: product}
    }
    logCollection.mapReduce(mapFunction, reduceFunction, outputControl, function (err, result) {
      if (err) { 
        callback(err); 
        return; 
      }
      var resultSet = [];
      //! post-processing
      for (var i = 0; i < result.length; i++) {
        //.....
      }
      callback(err, resultSet);
    });
  });
}

第二个查询:

function getAnotherData() {
  Log.native(function(err, logCollection) {
    var mapFunction = function() {
      //! Generate Grouping Key
      emit(dateFormatter(this.product), this.bad_qty)
    }
    var reduceFunction = function (key, values) {
      return Array.sum(values);
    }
    var outputControl = {
      out: {inline: 1},
      //! Filters
      query: {order_type: product}
    }
    logCollection.mapReduce(mapFunction, reduceFunction, outputControl, function (err, result) {
      if (err) { 
        callback(err); 
        return; 
      }
      var resultSet = [];
      //! post-processing
      for (var i = 0; i < result.length; i++) {
        //......
      }
      callback(err, resultSet);
    });
  });
}

正如您所看到的,这两个代码片段共享了许多共同的代码,只有三个地方不同(生成分组键、过滤器、后处理)。

所以我真的很想提取公共部分,让我的代码更干净,但没有成功。

我首先尝试让dateFromatter由回调提供,而不是像下面这样的硬编码:

function dateFormatter(data) {
  return data.emb_date.getFullYear() + "-" + (data.emb_date.getMonth() + 1)
}

function getSomeData(groupingKey) {
  // First-query
  Log.native(function(err, logCollection) {
    var mapFunction = function() {
      //! Generate Grouping Key
      emit(groupingKey(this.emb_date), this.bad_qty)
    }
    var reduceFunction = function (key, values) {
      return Array.sum(values);
    }
    var outputControl = {
      out: {inline: 1},
      //! Filters
      query: {order_type: product}
    }
    logCollection.mapReduce(mapFunction, reduceFunction, outputControl, function (err, result) {
      if (err) { 
        callback(err); 
        return; 
      }
      var resultSet = [];
      //! post-processing
      for (var i = 0; i < result.length; i++) {
        //.....
      }
      callback(err, resultSet);
    });
  });
}

但是没有任何运气,我不断地得到如下错误:

 MongoError: exception: ReferenceError: groupingKey is not defined near 'emit(groupingKey(this), this.bad_qty'  (line 3)
    at Object.toError (/home/brianhsu/zh800/dashboard/node_modules/sails-mongo/node_modules/mongodb/lib/mongodb/utils.js:114:11)

如果我想减少代码中那些重复的部分,该怎么办?

最后我发现我需要将名为"scope"的选项传递给mongodb,我提出了以下解决方案,效果很好。

exports.defineOn = function(options) {
  var model = options.model
  var groupingFunction = options.groupingFunction
  var mongoFilters = options.mongoFilters
  var customFilter = options.customFilter
  var converter = options.converter
  var sorting = options.sorting
  return function(callback) {
    model.native(function(err, collection) {
      var mapFunction = function() { emit(groupingFunction(this), this.bad_qty) }
      var reduceFunction = function(key, values) { return Array.sum(values); }
      var mapReduceOptions = {
        out: {inline: 1},
        query: mongoFilters,
        scope: {
          groupingFunction: groupingFunction, 
          mongoFilters: mongoFilters, 
          customFilter: customFilter,
          converter: converter
        }
      }
      var processCallback = function (err, result) {
        if (err) {
          callback(err);
          return;
        }
        if (sorting) {
          result.sort(sorting);
        }
        var resultSet = [];
        for (var i = 0; i < result.length; i++) {
          if (customFilter && customFilter(result[i])) {
            resultSet.push(converter(result[i]));
          } else if (!customFilter) {
            resultSet.push(converter(result[i]));
          }
        }
        callback(err, resultSet);
      }
      collection.mapReduce(mapFunction, reduceFunction, mapReduceOptions, processCallback);
    });
  }
}

用法:

function machineDetail (year, month, date, machine, callback) {
    var startDate = new Date(+year, +(month-1), +date);
    var endDate = new Date(+year, +(month-1), (+date) + 1);
    var mapReducer = MapReducer.defineOn({
      model: Log,
      groupingFunction: function(data) {
        return {date: data.emb_date, error: data.defact_id};
      },
      mongoFilters: {
        mach_id: machine,
        emb_date: {$gte: startDate, $lt: endDate}
      },
      converter: function (data) {
        return {
          name: data._id,
          value: data.value,
        };
      }
    });
    mapReducer(callback);
  }