首页/数据/NoSQL 速查/聚合 $graphLookup 图式遍历
MongoDB99 条

聚合 $graphLookup 图式遍历

$graphLookup 在集合内部沿引用关系递归查找(如汇报链、物料层级),支持出发字段、连接字段与深度上限。

NoSQL 速查数据更新于 2026-10-13

是什么

$graphLookup 在聚合管道里做递归查找:从一个起始值出发,沿着「本集合某字段」与「本集合另一个字段」的连接关系反复匹配,把沿途命中的文档收集到一个数组里。它适合组织汇报链、物料层级、分类树这类单集合内的自引用结构,不用把关系预先拍平或反复查库。

基本信息

语法{ $graphLookup: { from, startWith, connectFromField, connectToField, as, maxDepth, depthField, restrictSearchWithMatch } }
from被查找的集合,通常就是当前集合自身
startWith起始匹配值,可以是字面量、数组或字段表达式
connectFromField / connectToField递归的连接关系:用命中文档的某个字段去匹配下一个文档
as结果数组字段名
maxDepth递归深度上限;不设置表示不限深度,风险很大

典型使用场景

  • 组织架构:从某个员工出发向上找出全部汇报上级,或向下找出所有下属
  • 分类与物料层级:从子类目向上追溯到根类目,用于路径展示与权限继承
  • 依赖关系:找出某个服务的全部上游依赖,评估变更影响面
  • 路径回溯:在流量、物流链路里沿着引用关系回溯到起点
  • 配合过滤:用 restrictSearchWithMatch 只在有效状态的节点上继续递归

递归查找示例

递归查找示例
db.employees.aggregate([
  { $match: { name: "Alice" } },                 # 从一个人出发
  { $graphLookup: {
      from: "employees",
      startWith: "$manager",                       # 起点:直属上级
      connectFromField: "manager",                 # 命中文档继续沿 manager 往上找
      connectToField: "_id",
      as: "chain",                                 # 结果放在 chain 数组里
      maxDepth: 5,                                 # 必须给上限,避免无界递归
      depthField: "level"                          # 每个节点带出它离起点的层级
  } },
  { $project: { name: 1, "chain.name": 1, "chain.level": 1 } }
])

db.categories.aggregate([                        # 只在启用状态的节点上继续递归
  { $match: { slug: "laptop" } },
  { $graphLookup: { from: "categories", startWith: "$parent", connectFromField: "parent", connectToField: "_id", as: "ancestors", maxDepth: 8, restrictSearchWithMatch: { enabled: true } } }
])

参数逐项读法

参数作用注意点
from递归查找的集合指向本集合即自引用结构
startWith起始值或表达式常写成 "$parentField" 形式
connectFromField命中文档用于继续匹配的字段写错会立刻断链,结果只剩一层
connectToField被匹配的字段通常是 _id 或业务编码
as输出数组字段名结果是无序匹配集合,需要时自行排序
maxDepth最大递归深度必须设上限,否则可能无限展开
depthField记录层级的字段名用于过滤或展示层级
restrictSearchWithMatch递归时的额外过滤缩小每层匹配范围,减少无效展开
递归深度与匹配范围不设限时开销会快速上升:每一层都要在目标集合上做一次匹配,长链路或宽层级结构会成倍放大工作量。先用 maxDepth 与 restrictSearchWithMatch 把范围框住,再看性能是否可接受。
单集合内的浅层递归用 $graphLookup 很划算;一旦需要多跳变长路径、最短路径或环路检测,这类问题更适合图数据库。使用分片集合作为 from 时限制更多,动手前查对应版本手册。

易错点

  • 不设 maxDepth:深层或存在环状引用的数据会让递归无限展开,查询长时间不返回
  • connectFromField 与 connectToField 写反:关系链立刻断开,结果只有一层,却看不出语法错误
  • startWith 用了缺失字段:整个数组为空,容易误判成「没有上级」而不是「字段名写错」
  • 在大集合上做无过滤的递归:每层都是一次全集合匹配,深度越大代价越高,应先用 restrictSearchWithMatch 收敛

数据来源与参考

  • MongoDB Manual: $graphLookup
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌