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

使用MongoDB聚合框架统计数组相似元素——能否在$project阶段实现?

实现MongoDB聚合中$project阶段的答案统计需求

当然可以在$project阶段完成这个统计需求!MongoDB的聚合表达式(比如$reduce、$mergeObjects、$objectToArray等)能让我们直接在字段重塑阶段完成数组的计数和格式转换。下面针对你要的两种输出格式分别给出实现方案:

方案1:输出键值对对象格式

这个方案通过$reduce遍历answers数组累加计数,再用$mergeObjects动态更新计数对象:

db.collection.aggregate([
  {
    $project: {
      result: {
        $reduce: {
          input: "$answers",
          initialValue: {},
          in: {
            $mergeObjects: [
              "$$value",
              {
                [$$current]: {
                  $add: [
                    { $ifNull: ["$$value.$$current", 0] },
                    1
                  ]
                }
              }
            ]
          }
        }
      },
      _id: 0 // 隐藏_id字段,可选
    }
  }
])

代码解释:

  • $reduce:遍历answers数组,initialValue初始化一个空对象作为计数容器
  • $mergeObjects:每次遍历把当前的计数对象和新的键值对(当前选项+计数+1)合并
  • $ifNull:处理首次出现的选项,避免因键不存在导致的计算错误,默认计数为0

方案2:输出二维数组格式

如果需要二维数组格式,可以在方案1的基础上用$objectToArray把计数对象转成二维数组:

db.collection.aggregate([
  {
    $project: {
      result: {
        $objectToArray: {
          $reduce: {
            input: "$answers",
            initialValue: {},
            in: {
              $mergeObjects: [
                "$$value",
                {
                  [$$current]: {
                    $add: [
                      { $ifNull: ["$$value.$$current", 0] },
                      1
                    ]
                  }
                }
              ]
            }
          }
        }
      },
      _id: 0
    }
  }
])

额外说明:

如果你的需求是只统计multipleOptions中存在的选项(哪怕answers里没出现也显示0),可以稍微调整逻辑:先用$arrayToObject把multipleOptions转成初始计数为0的对象,再用$reduce更新计数,这样就能包含所有预设选项了。

比如针对第一个文档的multipleOptions,初始对象会是{"first":0,"second":0,"third":0,"forth":0},再遍历answers累加后得到完整的计数结果。


内容的提问来源于stack exchange,提问作者Milad ABC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:28:51