我有一个看起来像这样的模型
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
};
这比以前简洁得多,但它比以前快得多。
答案 0 :(得分:2)
两种可能性:
如果你担心那个帮助器,因为它不适合其余的代码,这看起来(从一个没有任何数据进行测试的角度来看)就像一个无点的替代方案:
R.lift(R.map)(R.compose(R.merge, R.pick(['group', 'key'])), R.prop('translations'))
您可能不需要所有这些then
。在第一次调用之后看起来没有任何异步。虽然将then
链接在一起通常很方便,但随着列表变长,它开始失去光彩。
您可能只是pipe
这些功能,并在单个then
内调用该组合。关键是,只要f1
,f2
,... fn
都是同步的,那么这些就是等价的:
someAsyncFn()
.then(f1)
.then(f2)
.then(f3)
.then(f4)
和
someAsyncFn().then(pipe(f1, f2, f3, f4))
这些都不是惊天动地,但要么可能有助于清理你的代码。