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

如何通过Mongo Aggregation实现指定条件的文档筛选?

MongoDB聚合筛选用户角色记录的正确实现

需求规则

  • 若用户存在active: true的manager角色记录,仅保留该用户的manager记录,忽略所有user角色记录
  • 若用户的manager角色记录active: false,保留该用户所有user角色记录(无论user的active状态)
  • 若用户无manager角色记录,保留其所有user角色记录;反之,无user记录则保留manager记录

示例数据集

[
  {
    role:"manager",
    user:"john",
    active:true
  },
  {
    role:"user",
    region:"us",
    user:"john",
    active:false
  },
  {
     role:"user",
    region:"czk",
    user:"john",
    active:false
  },
  {
    role:"user",
    region:"czk",
    user:"jane",
    active:false
  },
  {
    role:"user",
    region:"us",
    user:"jane",
    active:true
  },
  {
    role:"manager",
    user:"jane",
    active:false
  }
]

预期结果

获取索引0、3、4的文档,即:

[
  { role:"manager", user:"john", active:true },
  { role:"user", region:"czk", user:"jane", active:false },
  { role:"user", region:"us", user:"jane", active:true }
]

原方案问题

原聚合语句仅筛选active: true的manager和user记录,完全不符合需求逻辑——既无法处理用户存在active: false的manager时需保留所有user的情况,也未对用户的角色关联关系做判断。

正确聚合实现

我们需要先按用户分组,判断每个用户的角色状态,再根据规则筛选记录:

db.collection.aggregate([
  // 1. 按用户分组,收集所有记录并标记是否存在激活的manager
  {
    $group: {
      _id: "$user",
      records: { $push: "$$ROOT" },
      hasActiveManager: {
        $max: {
          $cond: [{ $and: [{ $eq: ["$role", "manager"] }, { $eq: ["$active", true] }] }, true, false]
        }
      }
    }
  },
  // 2. 根据分组标记筛选符合规则的记录
  {
    $project: {
      filteredRecords: {
        $filter: {
          input: "$records",
          as: "record",
          cond: {
            $switch: {
              branches: [
                // 情况1:存在激活的manager,仅保留manager记录
                {
                  case: "$hasActiveManager",
                  then: { $eq: ["$$record.role", "manager"] }
                },
                // 情况2:无激活manager,保留所有user记录;若用户只有一条manager记录(active:false)也保留
                {
                  case: { $not: "$hasActiveManager" },
                  then: {
                    $or: [
                      { $eq: ["$$record.role", "user"] },
                      { $and: [{ $eq: ["$$record.role", "manager"] }, { $eq: [{ $size: "$records" }, 1] }] }
                    ]
                  }
                }
              ],
              default: false
            }
          }
        }
      }
    }
  },
  // 3. 展开筛选后的记录数组
  { $unwind: "$filteredRecords" },
  // 4. 恢复原文档结构
  { $replaceRoot: { newRoot: "$filteredRecords" } }
])

逻辑说明

  1. 分组阶段:按用户聚合,收集该用户的所有记录,同时用$max和$cond判断是否存在激活的manager角色
  2. 筛选阶段:用$switch分情况处理规则:
    • 存在激活manager时,仅保留该用户的manager记录
    • 无激活manager时,保留所有user记录;若用户只有一条active: false的manager记录,也保留该记录
  3. 展开与替换根:将筛选后的数组展开,恢复为原文档格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 09:55:24