Ramda> Mongoose>数据结构操作

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

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> group> key> translation的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; } 

我知道了!

所以我正在寻找方法来清理这个代码/加快响应。 我的第一个尝试是使用辅助function的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 } 

但是我被帮助函数困扰,决定跳到“聚合”构造函数中,我的最终代码看起来像这样。

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

这并不比以前更简洁,但比以前快得多。

两种可能性:

  • 如果你担心这个助手,因为它不适合于其他的代码,这看起来(从没有任何数据的testing的angular度来看)就像一个无关的方法:

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

    您可以简单地将这些function连接在一起, then在一个内部调用组合。 重点是只要f1f2 ,… fn都是同步的,那么这些就是等价的:

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

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

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

Interesting Posts