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

MongoDB聚合中如何按组统计布尔字段isReserved的学生总数?

MongoDB聚合:统计关联组中已预留学生数的实现方案

问题场景

现有两个MongoDB集合:

  • Groups:结构为 {_id : ObjectId, title: String}
  • Students:结构为 {mainGroups: String, isReserved: Boolean}

其中Students的mainGroups字段是学生参与的所有组ID拼接成的字符串。当前聚合管道已能关联每个组对应的学生,并统计学生总数studentCount,需要新增totalStudentsReserved字段,统计每个组中isReserved: true的学生数量。

现有聚合代码:

[
  {
      $addFields: {
          gid: { $toString: "$_id" }
      }
  },
  {
    $lookup: {
        from: 'students',
        let: { groupId: "$gid" },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $regexMatch: {
                            input: "$mainGroups",
                            regex: { $concat: [".*", "$$groupId", ".*"] },
                            options: "i"
                        }
                    }
                }
            }
        ],
        as: "students"
    }
  },
  {
      $project: {
          _id: 1,
          gid: 1,
          title: 1,
          studentCount: { $size: "$students" }
      }
  }
]

解决方案

方案一:在$project阶段直接筛选统计

不需要额外的$group阶段,直接在$project中通过$filter和$size组合实现需求,修改后的完整管道如下:

[
  {
      $addFields: {
          gid: { $toString: "$_id" }
      }
  },
  {
    $lookup: {
        from: 'students',
        let: { groupId: "$gid" },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $regexMatch: {
                            input: "$mainGroups",
                            regex: { $concat: [".*", "$$groupId", ".*"] },
                            options: "i"
                        }
                    }
                }
            }
        ],
        as: "students"
    }
  },
  {
      $project: {
          _id: 1,
          gid: 1,
          title: 1,
          studentCount: { $size: "$students" },
          totalStudentsReserved: {
              $size: {
                  $filter: {
                      input: "$students",
                      cond: { $eq: ["$$this.isReserved", true] }
                  }
              }
          }
      }
  }
]

逻辑说明:

  • $filter遍历students数组,筛选出所有isReserved为true的元素,返回筛选后的新数组
  • $size获取该新数组的长度,即为当前组中已预留的学生总数

方案二:在$lookup内部提前统计(适合大数据量场景)

如果关联的学生数据量较大,可以在$lookup的内部管道中直接完成统计,减少后续数据传输和处理量:

[
  {
      $addFields: {
          gid: { $toString: "$_id" }
      }
  },
  {
    $lookup: {
        from: 'students',
        let: { groupId: "$gid" },
        pipeline: [
            {
                $match: {
                    $expr: {
                        $regexMatch: {
                            input: "$mainGroups",
                            regex: { $concat: [".*", "$$groupId", ".*"] },
                            options: "i"
                        }
                    }
                }
            },
            {
                $group: {
                    _id: null,
                    total: { $sum: 1 },
                    reservedTotal: { $sum: { $cond: [{ $eq: ["$isReserved", true] }, 1, 0] } }
                }
            }
        ],
        as: "studentStats"
    }
  },
  {
      $project: {
          _id: 1,
          gid: 1,
          title: 1,
          studentCount: { $arrayElemAt: ["$studentStats.total", 0] },
          totalStudentsReserved: { $arrayElemAt: ["$studentStats.reservedTotal", 0] }
      }
  }
]

逻辑说明:

  1. 内部管道先匹配出当前组对应的所有学生
  2. 用$group统计:
    • total:匹配到的学生总数($sum:1累加计数)
    • reservedTotal:用$cond判断,若isReserved为true则加1,否则加0,最终得到预留学生数
  3. 最后通过$arrayElemAt从studentStats数组中取出统计值(因为内部$group后只会生成一个统计文档)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:32:55