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

MongoDB聚合框架:按数组分组去重求和并存储结果的疑问

解决MongoDB按数组分组聚合后存储的问题

嘿,我来帮你搞定这个MongoDB的聚合问题!你想按document数组分组去重,对total字段求和,结果却卡在了$out操作——因为直接把数组作为_id没法正常存入目标集合,对吧?别担心,下面给你两种靠谱的解决方案,既能实现需求,又能顺利把结果存到集合里。

方案一:用哈希值转数组为分组键(MongoDB 4.0+适用)

我们可以先把document数组转换成唯一的哈希字符串,用这个哈希值来分组,最后再保留原数组字段。这样既保证了分组的唯一性,又能避开数组作为_id的问题。

聚合管道代码:

db.yourCollection.aggregate([
  // 给每个document数组生成唯一哈希值
  {
    $addFields: {
      documentHash: { $hash: "$document" }
    }
  },
  // 按哈希值分组,求和total,同时保留原数组(取第一个就行,同哈希对应同数组)
  {
    $group: {
      _id: "$documentHash",
      document: { $first: "$document" },
      total: { $sum: "$total" }
    }
  },
  // 生成新的ObjectId作为目标集合的_id,移除临时哈希字段
  {
    $addFields: {
      _id: ObjectId()
    }
  },
  // 将结果输出到目标集合(这里命名为uniqueDocuments,你可以改成自己的)
  {
    $out: "uniqueDocuments"
  }
])

为啥这么做?

  • $hash操作符会把数组转成固定长度的唯一字符串,相同数组生成的哈希值完全一致,不同数组的哈希值几乎不可能碰撞,分组绝对准确。
  • 分组后用$first拿原数组,因为同一哈希对应的数组肯定是一模一样的,不会有问题。
  • 最后生成标准的ObjectId当_id,符合MongoDB集合的常规文档结构,后续操作也更方便。

方案二:把数组拼接成字符串分组(兼容低版本MongoDB)

如果你用的MongoDB版本低于4.0,不支持$hash,那就用$reduce把数组里的value字段拼接成一个唯一字符串来当分组键。

聚合管道代码:

db.yourCollection.aggregate([
  // 把document数组的value按顺序拼接成字符串,用|当分隔符避免冲突
  {
    $addFields: {
      documentKey: {
        $reduce: {
          input: "$document",
          initialValue: "",
          in: {
            $concat: [
              "$$value",
              { $cond: [{ $eq: ["$$value", ""] }, "", "|"] },
              "$$this.value"
            ]
          }
        }
      }
    }
  },
  // 按拼接后的字符串分组,求和total,保留原数组
  {
    $group: {
      _id: "$documentKey",
      document: { $first: "$document" },
      total: { $sum: "$total" }
    }
  },
  // 生成新的ObjectId作为_id,删掉临时的拼接键
  {
    $addFields: {
      _id: ObjectId()
    }
  },
  // 输出到目标集合
  {
    $out: "uniqueDocuments"
  }
])

小细节提醒:

  • 用|当分隔符是为了避免类似["a", "bc"]和["ab", "c"]这种数组拼接成相同字符串的情况,保证分组的准确性。
  • 这个方法兼容性拉满,低版本MongoDB也能完美运行。

结果验证

不管用哪种方案,执行完聚合管道后,去查目标集合uniqueDocuments,就能得到你想要的结果:

{ "_id" : ObjectId("xxx"), "document" : [ { "value" : "a" }, { "value" : "b" }, { "value" : "c" } ], "total" : 9 },
{ "_id" : ObjectId("yyy"), "document" : [ { "value" : "b" }, { "value" : "c" } ], "total" : 2 }

内容的提问来源于stack exchange,提问作者Dr. Mza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:13:26