如何结合lookup与aggregate为Recipe文档添加总kcal属性?
解决方法
你已经迈出了很好的一步,实现了总重量的计算!要获取总千卡,我们只需要在聚合管道里多嵌套一层$lookup来关联每个配料对应的营养数据,然后计算每份配料的千卡再求和即可。
完整的聚合代码
const query = Recipe.aggregate([ // 第一步:关联Ingredients,同时嵌套关联对应的Nutrient { $lookup: { from: 'ingredients', // 对应Ingredient模型的集合名(Mongoose默认小写复数) localField: 'ingredients', foreignField: '_id', as: 'ingredients', // 在这个lookup内部,给每个配料关联对应的Nutrient pipeline: [ { $lookup: { from: 'nutrients', // 对应Nutrient模型的集合名 localField: 'nutrient', foreignField: '_id', as: 'nutrient' } }, { $unwind: '$nutrient' } // 把nutrient数组展开为单个对象(因为每个配料只关联一个营养项) ] } }, // 第二步:计算总重量和总千卡 { $addFields: { totalWeight: { $sum: '$ingredients.weightInGrams' }, // 保留你原来的总重量计算 totalKcal: { $sum: { // 遍历每个配料,计算单份千卡后求和 $map: { input: '$ingredients', as: 'ing', in: { $multiply: [ { $divide: ['$$ing.nutrient.kcalPerHundredGrams', 100] }, // 每克的千卡值 '$$ing.weightInGrams' // 配料重量 ] } } } }, // 可选:给每个配料单独加上计算后的千卡值,方便查看明细 ingredients: { $map: { input: '$ingredients', as: 'ing', in: { _id: '$$ing._id', weightInGrams: '$$ing.weightInGrams', nutrient: '$$ing.nutrient', ingredientKcal: { $multiply: [ { $divide: ['$$ing.nutrient.kcalPerHundredGrams', 100] }, '$$ing.weightInGrams' ] } } } } } } ]);
代码解释
嵌套的
$lookup:- 外层
$lookup先把Recipe关联的所有Ingredient数据拉取进来。 - 内层的
$lookup(放在pipeline里)为每个Ingredient关联对应的Nutrient数据,之后用$unwind把nutrient数组转成单个对象,避免后续计算时处理数组结构。
- 外层
总千卡计算:
- 用
$map遍历每个配料,通过公式(每百克千卡 / 100) * 配料重量计算单份配料的千卡。 - 再用
$sum把所有配料的千卡值加总,得到整个食谱的totalKcal。
- 用
可选的配料明细:
- 如果你需要查看每个配料单独的千卡值,可以用
$map给每个Ingredient对象添加ingredientKcal字段,方便调试或返回明细数据。
- 如果你需要查看每个配料单独的千卡值,可以用
这样执行聚合后,每个Recipe文档就会带上totalWeight和totalKcal两个汇总属性啦!
内容的提问来源于stack exchange,提问作者Macondele
相关产品推荐
相关产品推荐

