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

如何针对可变长度数组应用MongoDB的$group聚合操作

嘿,我来帮你搞定MongoDB里带可变长度数组的文档的$group聚合操作!先把你的文档结构贴出来方便参考:

{ 
  "_id" : ObjectId("5ac392f15c592414ec99d630"), 
  "nv" : "de", 
  "nid" : 1.0, 
  "coc" : 3.0, 
  "seg" : { 
    "segid" : 0.0, 
    "attv" : [ 
      { "id" : 1.0, "v" : 5.0 }, 
      { "id" : 2.0, "v" : 4.0 } 
    ], 
    "devattv" : [ 
      { "id" : 1.0, "v" : 2.0, "t" : 1.0 }, 
      { "id" : 1.0, "v" : 3.0, "t" : ... } 
    ] 
  } 
}

下面分几种常见场景给你拆解,一步步来:

场景1:按顶层字段分组,聚合数组内的统计值

比如你想按nv字段分组,计算所有seg.attv.v的总和、平均值,或者统计数组元素的总数量。这时候需要先用$unwind把数组拆成单个文档,再做分组聚合:

db.collection.aggregate([
  // 把attv数组拆分成独立文档,每个数组元素对应一条新文档
  { $unwind: "$seg.attv" },
  // 按顶层的nv字段分组,聚合数组内的数值
  {
    $group: {
      _id: "$nv", // 分组键,这里选顶层的nv字段
      totalAttvValue: { $sum: "$seg.attv.v" }, // 所有attv.v的总和
      avgAttvValue: { $avg: "$seg.attv.v" }, // 所有attv.v的平均值
      totalAttvItems: { $sum: 1 } // 统计所有attv数组元素的总数量
    }
  }
])

小提示:如果数组可能为空,默认$unwind会丢弃空数组的文档,你可以加参数保留它们:
{ $unwind: { path: "$seg.attv", preserveNullAndEmptyArrays: true } }

场景2:按数组内的字段分组,关联其他字段聚合

比如你想按seg.attv.id分组,计算每个id对应的v的总和,同时收集对应的顶层nid值:

db.collection.aggregate([
  { $unwind: "$seg.attv" },
  {
    $group: {
      _id: "$seg.attv.id", // 按数组内的id字段作为分组键
      totalV: { $sum: "$seg.attv.v" }, // 该id对应的v值总和
      distinctNids: { $addToSet: "$nid" } // 收集关联的顶层nid,自动去重
    }
  }
])

场景3:不拆分数组,直接聚合嵌套数组内容

如果不想用$unwind导致数据膨胀(比如数组元素很多时),可以用$map、$reduce这类数组操作符,在文档内部先处理数组,再做分组:

比如按nid分组,把每个文档的devattv数组按id聚合v的总和:

db.collection.aggregate([
  {
    $group: {
      _id: "$nid",
      // 先把每个文档的devattv按id合并v值,再收集到数组里
      tempDevattv: {
        $push: {
          $reduce: {
            input: "$seg.devattv",
            initialValue: {},
            in: {
              id: "$$this.id",
              totalV: { $add: ["$$value.totalV", "$$this.v"] }
            }
          }
        }
      }
    }
  },
  // 再把临时数组里的同id数据合并最终总和
  {
    $addFields: {
      finalDevattv: {
        $reduce: {
          input: "$tempDevattv",
          initialValue: [],
          in: {
            $concatArrays: [
              "$$value",
              [{ id: "$$this.id", totalV: "$$this.totalV" }]
            ]
          }
        }
      }
    }
  }
])

关键注意事项

  • 多次$unwind多个数组会产生笛卡尔积,数据量会大幅增加,谨慎使用;
  • 对于超大规模的数组聚合,优先考虑$unwind+$group的组合,性能更优;
  • 如果需要保留原数组结构,再结合$push、$addToSet把聚合后的元素重新组装成数组。

内容的提问来源于stack exchange,提问作者Alex P.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:42:49