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

Mongoose/MongoDB:如何在自引用结构中统计开发人员下属数量

问题描述

我有一个员工(Employees)集合,采用员工与经理自引用的结构,通过_id和managerIDs字段关联,经理本身也是员工。

员工文档示例:

{
  "_id": "61b9f07300127afb99f8c1ea",
  "title": "Developer",
  "firstName": "Jack",
  "lastName": "Strauss",
  "managerIDs": [
    "61cedf84800749316306c6da"
  ],
  "deptID": "61b9f073267500832f5d94d0"
},
{
  "_id": "61cedf84800749316306c6da",
  "title": "Sr. Developer",
  "firstName": "Richard",
  "lastName": "Haris",
  "managerIDs": null,
  "deptID": "61b9f073267500832f5d94d0"
},
{
  "_id": "61cedf17800749316306c6cf",
  "title": "Manager App Development",
  "firstName": "Arnold",
  "lastName": "Cliff",
  "deptID": "61b9f073267500832f5d94d0"
},
{
  "_id": "61d4503e1223496ab8a5ae3c",
  "title": "Developer",
  "firstName": "Andrew",
  "lastName": "Turner",
  "managerIDs": [
    "61cedf17800749316306c6cf",
    "61cedf84800749316306c6da"
  ],
  "deptID": "61b9f073267500832f5d94d0"
}

规则说明:

  • 员工可无、1个或多个经理(因此使用数组存储managerIDs)。
  • managerIDs字段可为null、undefined、单个ID或多个ID数组。
  • Developer(开发人员)不能担任经理,不会被纳入经理列表,且只有开发人员会被管理。
  • 所有非开发人员均为经理,需统计其管理的开发人员数量(即其ID出现在开发人员的managerIDs数组中的次数)。

我需要编写查询来列出所有经理的姓名、职位及管理的开发人员数量,尝试过MongoDB聚合的$lookup但未成功,请问如何在MongoDB或Mongoose中编写该查询?


解决方案

可以通过MongoDB的聚合管道实现,核心思路是先筛选出所有经理,再关联统计每个经理对应的开发人员数量,具体实现如下:

MongoDB聚合查询代码

db.employees.aggregate([
  // 筛选出所有经理(排除职位含"Developer"的员工)
  {
    $match: {
      title: { $not: { $regex: /Developer/i } }
    }
  },
  // 关联匹配当前经理管理的开发人员
  {
    $lookup: {
      from: "employees",
      let: { managerId: "$_id" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                // 只匹配开发人员
                { $regexMatch: { input: "$title", regex: /Developer/i } },
                // 处理managerIDs为null/undefined的情况,确保匹配逻辑不报错
                { $in: ["$$managerId", { $ifNull: ["$managerIDs", []] }] }
              ]
            }
          }
        }
      ],
      as: "managedDevelopers"
    }
  },
  // 整理输出字段并统计管理人数
  {
    $project: {
      _id: 0,
      fullName: { $concat: ["$firstName", " ", "$lastName"] },
      title: 1,
      managedCount: { $size: "$managedDevelopers" }
    }
  }
])

代码说明:

  1. $match阶段:通过不区分大小写的正则匹配,排除所有职位包含"Developer"的员工,只保留经理。
  2. $lookup阶段:使用子管道关联员工集合,精准筛选出职位为开发人员且managerIDs包含当前经理ID的记录,用$ifNull处理managerIDs为空的场景,避免查询报错。
  3. $project阶段:拼接经理的全名,用$size获取关联到的开发人员数组长度(即管理人数),并整理输出所需字段。

Mongoose中的写法

假设你的Mongoose模型名为Employee,写法与原生MongoDB聚合基本一致:

const managers = await Employee.aggregate([
  {
    $match: {
      title: { $not: { $regex: /Developer/i } }
    }
  },
  {
    $lookup: {
      from: "employees", // 对应Mongoose模型的集合名,通常为小写复数形式
      let: { managerId: "$_id" },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                { $regexMatch: { input: "$title", regex: /Developer/i } },
                { $in: ["$$managerId", { $ifNull: ["$managerIDs", []] }] }
              ]
            }
          }
        }
      ],
      as: "managedDevelopers"
    }
  },
  {
    $project: {
      _id: 0,
      fullName: { $concat: ["$firstName", " ", "$lastName"] },
      title: 1,
      managedCount: { $size: "$managedDevelopers" }
    }
  }
]);

console.log(managers);

测试结果

针对示例数据,查询输出结果为:

[
  {
    "title": "Manager App Development",
    "fullName": "Arnold Cliff",
    "managedCount": 1
  }
]

(注:Richard的职位是Sr. Developer,属于开发人员范畴,不会被纳入经理列表;Arnold作为经理,管理了Andrew这1名开发人员)


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 02:06:52