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

如何在MongoDB的find查询$expr中通过$reduce获取唯一计数?

MongoDB查询:统计数组中去重后val为true的id数量≥2的文档

数据结构

集合中文档包含values对象数组,每个元素有id和val字段,示例数据如下:

[
  {
    "values": [
      { "id": "123", "val": true },
      { "id": "456", "val": true },
      { "id": "789", "val": false }
    ]
  },
  {
    "values": [
      { "id": "123", "val": true },
      { "id": "123", "val": true },
      { "id": "123", "val": false }
    ]
  },
  {
    "values": [
      { "id": "234", "val": false },
      { "id": "567", "val": false }
    ]
  }
]

原查询及结果

此前已实现查询val为true且数组中该实例数量≥2的文档,查询语句如下:

db.collection.find({
  values: {
    "$elemMatch": {
      val: true
    }
  },
  $expr: {
    $gte: [
      {
        $reduce: {
          input: "$values",
          initialValue: 0,
          in: {
            $sum: [
              "$$value",
              {
                $cond: [
                  { $eq: ["$$this.val", true] },
                  1,
                  0
                ]
              }
            ]
          }
        }
      },
      2
    ]
  }
})

该查询返回结果:

[
  {
    "values": [
      { "id": "123", "val": true },
      { "id": "456", "val": true },
      { "id": "789", "val": false }
    ]
  },
  {
    "values": [
      { "id": "123", "val": true },
      { "id": "123", "val": true },
      { "id": "123", "val": false }
    ]
  }
]

需求更新

现在需要调整统计逻辑:仅计算不同id中val为true的数量,要求该数量≥2,最终只保留第一个符合条件的文档(即上述结果中的第一个文档)。已知$group可用于去重,但不确定如何整合到现有查询中,且实际场景需保留$elemMatch作为最优过滤方案。

解决方案

我们可以在$expr中先对values数组里val为true的元素按id去重,再统计唯一id的数量,判断是否≥2。以下提供两种实现方式:

方式一:$filter + $map + $addToSet + $size

先过滤出val为true的元素,提取对应的id后去重,再统计去重后的数量:

db.collection.find({
  values: { "$elemMatch": { val: true } },
  $expr: {
    $gte: [
      {
        $size: {
          $addToSet: {
            $map: {
              input: { $filter: { input: "$values", cond: { $eq: ["$$this.val", true] } } },
              as: "item",
              in: "$$item.id"
            }
          }
        }
      },
      2
    ]
  }
})

方式二:$reduce维护唯一id集合

用$reduce遍历数组,只收集val为true且未统计过的id,最后统计集合长度:

db.collection.find({
  values: { "$elemMatch": { val: true } },
  $expr: {
    $gte: [
      {
        $size: {
          $reduce: {
            input: "$values",
            initialValue: [],
            in: {
              $cond: [
                { $and: [{ $eq: ["$$this.val", true] }, { $not: { $in: ["$$this.id", "$$value"] } }] },
                { $concatArrays: ["$$value", ["$$this.id"]] },
                "$$value"
              ]
            }
          }
        }
      },
      2
    ]
  }
})

两种方式均保留了$elemMatch的前置过滤(用于快速排除无val: true元素的文档,提升查询性能),最终只会返回第一个符合去重后数量≥2条件的文档。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 00:05:15