如何在MongoDB中用$reduce将数组转为对象,避开$unwind与$group?
问题描述
我有如下结构的文档:
{ venue: 'La Rocca', shifts: [ { type: 'Morning', employee: 'Jake Sullivan' }, { type: 'Morning', employee: 'Paul Smith' }, { type: 'Evening', employee: 'Mike Sullivan' }, { type: 'Morning', employee: 'Mike Belloney' }, ] }
希望通过$reduce生成如下结构的结果:
{ counts: { morning: 3, evening: 1, }, }
请问能否在不使用$unwind和$group的前提下实现该需求?如果可以,具体该如何操作?
解决方案
完全可以通过$reduce实现,不需要用到$unwind和$group。核心思路是用$reduce遍历shifts数组,对每个元素的type进行统一处理后累加对应班次的计数。
具体的聚合管道如下:
db.collection.aggregate([ { $addFields: { counts: { $reduce: { input: "$shifts", initialValue: { morning: 0, evening: 0 }, in: { morning: { $add: [ "$$value.morning", { $cond: [{ $eq: [{ $toLower: "$$this.type" }, "morning"] }, 1, 0] } ] }, evening: { $add: [ "$$value.evening", { $cond: [{ $eq: [{ $toLower: "$$this.type" }, "evening"] }, 1, 0] } ] } } } } } }, // 可选:如果只保留counts字段,可添加此阶段 { $project: { venue: 0, shifts: 0 } } ])
代码说明
$reduce的input指定要遍历的目标数组$shifts;initialValue初始化计数对象,将morning和evening的初始值设为0;in逻辑块中,先用$toLower统一班次类型的大小写(避免大小写敏感导致计数错误),再通过$cond判断当前元素的班次类型,匹配则加1,否则加0,最终累加到$$value的对应计数属性上;$addFields用于将生成的counts字段追加到原文档中,可选的$project阶段可以移除不需要的原始字段。
通过这个管道就能直接得到目标计数结构,全程无需拆分或分组数组。
内容的提问来源于stack exchange,提问作者Mike M
相关产品推荐
相关产品推荐

