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

MongoDB聚合管道:按用户分组并保留计数

按用户分组统计工单信息的MongoDB聚合方案

我来帮你搞定这个需求,根据你给出的User和Ticket Schema,我整理了两种聚合管道方案,分别对应不同的统计深度:


基础版:快速统计已分配/已解决工单数量

如果只需要每个用户的assignedTickets和resolvedTickets的总数,不需要关联工单的详细信息,这个方案性能最优:

db.users.aggregate([
  // 先计算每个用户的两类工单数量
  {
    $addFields: {
      assignedCount: { $size: "$assignedTickets" },
      resolvedCount: { $size: "$resolvedTickets" }
    }
  },
  // 按用户分组(因为每个文档就是一个用户,这里分组是为了保留所有非数组字段)
  {
    $group: {
      _id: "$_id",
      firstName: { $first: "$firstName" },
      lastName: { $first: "$lastName" },
      assignedCount: { $first: "$assignedCount" },
      resolvedCount: { $first: "$resolvedCount" },
      createdAt: { $first: "$createdAt" },
      updatedAt: { $first: "$updatedAt" }
    }
  },
  // 可选:格式化输出,把_id改成更直观的userId
  {
    $project: {
      userId: "$_id",
      firstName: 1,
      lastName: 1,
      assignedCount: 1,
      resolvedCount: 1,
      createdAt: 1,
      updatedAt: 1,
      _id: 0
    }
  }
])

这里用$size直接读取数组长度,避免了关联集合的开销,适合只需要数量的场景。


进阶版:关联工单详情,统计各类型工单数量

如果需要进一步统计已分配/已解决工单中不同type的数量(比如bug、feature各有多少),就需要先关联Ticket集合再统计:

db.users.aggregate([
  // 关联已分配的工单详情
  {
    $lookup: {
      from: "tickets",
      localField: "assignedTickets",
      foreignField: "_id",
      as: "assignedTicketDetails"
    }
  },
  // 关联已解决的工单详情
  {
    $lookup: {
      from: "tickets",
      localField: "resolvedTickets",
      foreignField: "_id",
      as: "resolvedTicketDetails"
    }
  },
  // 计算总数+各类型统计
  {
    $addFields: {
      // 已分配工单总数
      assignedCount: { $size: "$assignedTicketDetails" },
      // 已分配工单按类型统计,转成键值对格式
      assignedTypeStats: {
        $arrayToObject: {
          $map: {
            input: { $setUnion: ["$assignedTicketDetails.type"] },
            as: "type",
            in: {
              k: "$$type",
              v: {
                $size: {
                  $filter: {
                    input: "$assignedTicketDetails",
                    cond: { $eq: ["$$this.type", "$$type"] }
                  }
                }
              }
            }
          }
        }
      },
      // 已解决工单总数
      resolvedCount: { $size: "$resolvedTicketDetails" },
      // 已解决工单按类型统计
      resolvedTypeStats: {
        $arrayToObject: {
          $map: {
            input: { $setUnion: ["$resolvedTicketDetails.type"] },
            as: "type",
            in: {
              k: "$$type",
              v: {
                $size: {
                  $filter: {
                    input: "$resolvedTicketDetails",
                    cond: { $eq: ["$$this.type", "$$type"] }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  // 分组保留用户信息
  {
    $group: {
      _id: "$_id",
      firstName: { $first: "$firstName" },
      lastName: { $first: "$lastName" },
      assignedCount: { $first: "$assignedCount" },
      assignedTypeStats: { $first: "$assignedTypeStats" },
      resolvedCount: { $first: "$resolvedCount" },
      resolvedTypeStats: { $first: "$resolvedTypeStats" },
      createdAt: { $first: "$createdAt" },
      updatedAt: { $first: "$updatedAt" }
    }
  },
  // 可选:格式化输出
  {
    $project: {
      userId: "$_id",
      firstName: 1,
      lastName: 1,
      assignedCount: 1,
      assignedTypeStats: 1,
      resolvedCount: 1,
      resolvedTypeStats: 1,
      createdAt: 1,
      updatedAt: 1,
      _id: 0
    }
  }
])

关键逻辑说明

  • $lookup:用来关联tickets集合,把用户的工单ID转换成实际的工单文档,方便后续统计类型。
  • $setUnion:先提取所有不重复的工单类型,避免重复统计。
  • $arrayToObject + $map:把类型数组转换成{"bug": 5, "feature": 3}这种直观的键值对格式,便于前端展示或后续处理。

如果需要优化性能,比如只统计特定类型的工单,可以在$lookup里加入pipeline参数提前过滤工单,减少数据传输量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:13:55