Ramda>猫鼬>数据结构操作

时间:2017-03-08 19:26:47

标签: node.js mongoose ramda.js

我有一个看起来像这样的模型

var TermSchema = new Schema({
group: {type:String},
key: {type:String},
translations:[{
  clientId:{type:Number,default:config.gdgId},
  lang:{type:String},
  val:{type:String},
  needsTrans:{type:Boolean,default:false}
}],
updatedAt:{type:Date, default: Date.now},
updatedBy:{type:String, default: ''},
createdBy:{type:String, default: ''},
createdAt:{type:String, default: Date.now},
comments:{type:String, default: ''},
softDelete:{type:Boolean,default: false}

});

但是我需要将特定客户端翻译的实例转换为lang>的i18n格式。组>键>翻译。我的原始代码看起来像这样

function companyTerms(clientId){
var deferred = q.defer();
var companyObj = {'en-US':{},'de-DE':{},'en-GB':{},'es-SP':{},'fr-FR':{},'it-IT':{},'nl-NL':{},'pt-BR':{},'zh-CN':{}};
Term.find({'translations':{$elemMatch:{'clientId':clientId}}, 'softDelete': false}, function(err,terms){
    _.each(terms,function(term){
      _.each(term.translations,function(trans){
        if(companyObj[trans.lang]){
          companyObj[trans.lang][term.group] = {};
        }
      })
    })
    _.each(terms,function(term){
      _.each(term.translations,function(trans){
        if (trans.clientId == clientId && companyObj[trans.lang]) {
          companyObj[trans.lang][term.group][term.key] = trans.val;
        }
      })
    })
    deferred.resolve(companyObj);
  })
  return deferred.promise;
  }     

我知道的总数!

所以我一直在寻找清理此代码/加快响应速度的方法。我的第一次尝试是使用带有辅助函数的Ramda库。

function addToLang(groupObject){
let mapValues = obj => {
  obj['group'] = groupObject['group']
  obj['key'] = groupObject['key']
  return obj
  }
  return R.map(mapValues, groupObject.translations)

}

function companyTerms(clientId){
 return Term.find({'translations':{$elemMatch:{'clientId':clientId}},  'softDelete': false})
  .then(R.map(R.pick(['group','translations','key'])))
  .then(R.map(addToLang))//Adds group field to each translation object
  .then(R.flatten())//Flattens the different key objects
  .then(R.filter(R.propEq('clientId',parseInt(clientId))))//Filters out non-client translations
  .then(R.groupBy(R.prop('lang')))//Groups by language
  .then(R.map(R.groupBy(R.prop('group'))))//Sub-groups by group
  .then(R.map(R.map(R.groupBy(R.prop('key')))))//Has key as final group-value
  .then(R.map(R.map(R.map(R.pick(['key'])))))//Removes all other meta-data
}

但我对辅助函数感到恼火,并决定跳进'aggregate'构造函数,我的最终代码看起来像这样。

  function companyTerms(clientId){
return Term.aggregate([
  {
    "$unwind":"$translations"
  },{
    "$match":{
      "translations.clientId":parseInt(clientId),
      "softDelete":false
    }
  },{
    "$project":{
      key:"$key",
      group:"$group",
      lang:'$translations.lang',
    }
  }])
  .then(R.groupBy(R.prop('lang')))//Groups by language
  .then(R.map(R.groupBy(R.prop('group'))))//Sub-groups by group
  .then(R.map(R.map(R.groupBy(R.prop('key')))))//Has key as final group-value
  .then(R.map(R.map(R.map(R.pick(['key'])))))//Removes all other meta-data
};

这比以前简洁得多,但它比以前快得多。

1 个答案:

答案 0 :(得分:2)

两种可能性:

  • 如果你担心那个帮助器,因为它不适合其余的代码,这看起来(从一个没有任何数据进行测试的角度来看)就像一个无点的替代方案:

    R.lift(R.map)(R.compose(R.merge, R.pick(['group', 'key'])), R.prop('translations'))
    
  • 您可能不需要所有这些then。在第一次调用之后看起来没有任何异步。虽然将then链接在一起通常很方便,但随着列表变长,它开始失去光彩。

    您可能只是pipe这些功能,并在单个then内调用该组合。关键是,只要f1f2,... fn都是同步的,那么这些就是等价的:

    someAsyncFn()
      .then(f1)
      .then(f2)
      .then(f3)
      .then(f4)
    

    someAsyncFn().then(pipe(f1, f2, f3, f4))
    

这些都不是惊天动地,但要么可能有助于清理你的代码。