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

如何用MongoDB聚合管道按合法提示组合分组统计

MongoDB 4.4.22 聚合管道实现合法提示组合统计

现有文档结构

[
  {
    _id: ObjectId("6481b9762f11910c77d977ae"),
    hints: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint1" },
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint2" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint3" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint4" }
    ]
  },
  {
    _id: ObjectId("6168b9751000006e9d436bd1"),
    hints: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint1" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint3" }
    ]
  }
]

需求说明

需要统计每个合法提示组合的出现记录数,规则如下:

  • 合法组合要求同一creatorId不能重复出现
  • 默认每条记录包含所有创作者的提示,无需处理部分组合的情况
  • 提示的唯一性由creatorId+textValue共同决定,textValue相同但creatorId不同的提示算不同提示

问题

能否仅通过MongoDB聚合管道实现该需求?尝试过多种管道写法,但卡在单条记录中同一创作者存在多个提示的情况,无法生成符合要求的组合统计。

期望结果

[
  {
    _id: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint1" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint3" }
    ],
    count: 2
  },
  {
    _id: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint1" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint4" }
    ],
    count: 1
  },
  {
    _id: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint2" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint3" }
    ],
    count: 1
  },
  {
    _id: [
      { creatorId: "093c90be-8f19-45de-89ab-20070ef6d3f5", textValue: "hint2" },
      { creatorId: "575b9c75-c89d-4505-aec5-b001d8836845", textValue: "hint4" }
    ],
    count: 1
  }
]

解决方案:聚合管道实现

可以通过聚合管道完成,核心思路是先按creatorId分组整理提示,再生成所有合法组合,最后统计组合出现次数。具体管道如下:

db.collection.aggregate([
  // 1. 按creatorId分组,将同一创作者的提示整理到数组中
  {
    $unwind: "$hints"
  },
  {
    $group: {
      _id: {
        docId: "$_id",
        creatorId: "$hints.creatorId"
      },
      hints: { $push: "$hints" }
    }
  },
  {
    $group: {
      _id: "$_id.docId",
      creatorHints: {
        $push: {
          creatorId: "$_id.creatorId",
          hints: "$hints"
        }
      }
    }
  },
  // 2. 递归生成所有创作者提示的笛卡尔积(即合法组合)
  {
    $addFields: {
      combinations: {
        $reduce: {
          input: "$creatorHints",
          initialValue: [[]],
          in: {
            $concatArrays: {
              $map: {
                input: "$$value",
                as: "existing",
                in: {
                  $map: {
                    input: "$$this.hints",
                    as: "hint",
                    in: { $concatArrays: ["$$existing", ["$$hint"]] }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  // 3. 展开所有组合,为统计做准备
  { $unwind: "$combinations" },
  // 4. 对组合排序,确保相同内容的组合结构一致(避免因顺序不同被视为不同组合)
  {
    $addFields: {
      sortedCombination: {
        $sortArray: {
          input: "$combinations",
          sortBy: { creatorId: 1, textValue: 1 }
        }
      }
    }
  },
  // 5. 按排序后的组合分组统计出现次数
  {
    $group: {
      _id: "$sortedCombination",
      count: { $sum: 1 }
    }
  },
  // 6. 调整输出字段顺序(可选)
  { $project: { _id: 1, count: 1 } }
])

步骤解释

  1. 按创作者整理提示:先拆分hints数组,再按文档ID+创作者ID分组,把同一创作者在同一条记录里的所有提示整理到单独的数组中,得到每个文档下各创作者的提示集合。
  2. 生成笛卡尔积组合:用$reduce和$map嵌套,递归生成所有创作者提示的笛卡尔积,这样每个组合里每个创作者只会出现一次,符合合法组合要求。
  3. 组合排序去重:对每个组合按creatorId和textValue排序,确保内容相同但顺序不同的组合被视为同一个,避免统计错误。
  4. 统计组合次数:按排序后的组合分组,统计每个组合出现的记录数,得到最终结果。

内容的提问来源于stack exchange,提问作者Shaked Vitkon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 10:17:49