You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 13:18:00