本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
$graphLookup
8.0.2 版中的新内容。
Amazon DocumentDB 中的$graphLookup聚合阶段对集合执行递归搜索。对于每个输入文档,从一个或多个值$graphLookup开始,重复将连接字段与目标字段进行匹配,沿着匹配文档链进行匹配,直到没有更多匹配项或达到可选的递归深度。这对于遍历类图形或分层数据(例如组织报告结构、类别树或网络关系)很有用。
参数
-
from:要递归搜索的目标集合。该from集合必须在同一个数据库中。 -
startWith:该表达式指定递归搜索开始时使用的一个或多个值。将该值与from集合中文档connectToField的值进行比较。如果startWith计算结果为数组,则搜索将同时对所有数组元素运行。 -
connectFromField:字段名称,其值用于连接递归搜索中的下一个文档。如果该值是一个数组,则将分别跟踪每个元素进行遍历。 -
connectToField:from集合中与的值匹配的字段名称connectFromField。 -
as:添加到每个输出文档的数组字段的名称。此字段包含在递归搜索期间找到的文档。有关这些文档顺序的信息,请参阅以下 “行为” 部分中的结果排序项目。 -
maxDepth:一个非负整数,它指定初始查找后要执行的最大递归迭代次数。此参数为可选的。值仅0执行初始匹配,不执行递归。如果省略maxDepth,搜索将以递归方式继续,直到没有更多匹配的文档。 -
depthField:要添加到as数组中每个文档的字段的名称,该字段包含找到该文档的递归深度。此参数为可选的。深度以 a 表示NumberLong并从零开始,因此初始查找对应的深度为0。 -
restrictSearchWithMatch:指定应用于搜索文档的附加匹配条件的文档。此参数为可选的。该条件使用与$match阶段相同的查询语法,不能包含聚合表达式。
注意
该$graphLookup阶段受 100 MB 内存限制且不支持allowDiskUse:true。超过此限制的操作会返回错误。如果聚合包括其他阶段,则该allowDiskUse:true选项对这些阶段仍然有效。
行为
-
Cross-collection 遍历:设置为
from要搜索的集合。这可以是管道运行的相同集合,也可以是同一个数据库中的不同集合。 -
结果排序:
as数组中的文档不按任何保证顺序返回。
示例(MongoDB Shell)
以下示例用于$graphLookup遍历员工报告层次结构,对于每位员工,返回其上方的完整经理链。
以下命令在 mongosh shell 中运行,用于插入建立报告层次结构的示例员工文档:
db.employees.insertMany([ { _id: 1, name: "Dev", reportsTo: "Eliot" }, { _id: 2, name: "Eliot", reportsTo: "Ron" }, { _id: 3, name: "Ron", reportsTo: "Andrew" }, { _id: 4, name: "Andrew", reportsTo: "Asya" }, { _id: 5, name: "Asya" } ]);
以下聚合在新reportingHierarchy数组中返回每位员工的完整管理链:
db.employees.aggregate([ { $graphLookup: { from: "employees", startWith: "$reportsTo", connectFromField: "reportsTo", connectToField: "name", as: "reportingHierarchy", depthField: "level" } } ]);
此操作返回以下输出:
[
{
_id: 1,
name: 'Dev',
reportsTo: 'Eliot',
reportingHierarchy: [
{ _id: 2, name: 'Eliot', reportsTo: 'Ron', level: 0 },
{ _id: 3, name: 'Ron', reportsTo: 'Andrew', level: 1 },
{ _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 2 },
{ _id: 5, name: 'Asya', level: 3 }
]
},
{
_id: 2,
name: 'Eliot',
reportsTo: 'Ron',
reportingHierarchy: [
{ _id: 3, name: 'Ron', reportsTo: 'Andrew', level: 0 },
{ _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 1 },
{ _id: 5, name: 'Asya', level: 2 }
]
},
{
_id: 3,
name: 'Ron',
reportsTo: 'Andrew',
reportingHierarchy: [
{ _id: 4, name: 'Andrew', reportsTo: 'Asya', level: 0 },
{ _id: 5, name: 'Asya', level: 1 }
]
},
{
_id: 4,
name: 'Andrew',
reportsTo: 'Asya',
reportingHierarchy: [
{ _id: 5, name: 'Asya', level: 0 }
]
},
{
_id: 5,
name: 'Asya',
reportingHierarchy: []
}
]
每个员工文档都会获得一个包含递归匹配的经理文档的reportingHierarchy数组。该level字段记录了找到每个管理器的递归深度。Asya 没有reportsTo值,所以她的reportingHierarchy数组是空的。
使用 maxDepth 和限制的示例SearchWithMatch (MongoDB Shell)
以下示例遍历人与人之间的联系网络,用于maxDepth限制递归并restrictSearchWithMatch仅包含符合附加条件的文档。搜索会查找起始人物的人际关系,深度可达两层,只保留hobbies数组中包含的人golf。
以下命令在 mongosh shell 中运行,用于插入示例文档,其中每个人的friends指向通过单向连接链向前移动:
db.people.insertMany([ { _id: 1, name: "Tanya", friends: [ "Carole", "Shirley" ], hobbies: [ "tennis", "golf" ] }, { _id: 2, name: "Carole", friends: [ "Joseph" ], hobbies: [ "archery", "golf" ] }, { _id: 3, name: "Joseph", friends: [ "Angelo" ], hobbies: [ "tennis", "golf" ] }, { _id: 4, name: "Angelo", friends: [ "Miguel" ], hobbies: [ "travel", "golf" ] }, { _id: 5, name: "Miguel", friends: [], hobbies: [ "golf" ] }, { _id: 6, name: "Shirley", friends: [], hobbies: [ "frisbee" ] } ]);
以下聚合从 Tanya 开始,遍历她的人脉网络,深度可达两层,只保留那些列golf为业余爱好的人:
db.people.aggregate([ { $match: { name: "Tanya" } }, { $graphLookup: { from: "people", startWith: "$friends", connectFromField: "friends", connectToField: "name", as: "golfConnections", maxDepth: 2, restrictSearchWithMatch: { hobbies: "golf" } } }, { $project: { name: 1, "golfConnections.name": 1 } } ]);
此操作返回以下输出:
[
{
_id: 1,
name: 'Tanya',
golfConnections: [
{ name: 'Carole' },
{ name: 'Joseph' },
{ name: 'Angelo' }
]
}
]
仅包括hobbies数组包含golf的连接,并且遍历在两级递归后停止。雪莉之所以被排除在外,是因为她没有列出golf,而米格尔被排除在外,是因为他离Tanya还有三个等级,除此之外。maxDepth 2由于连接形成单向链,从不指向 Tanya,因此在递归搜索期间起始文档不匹配。
代码示例
要查看使用 MongoDB 驱动程序从第一个示例中构建员工报告层次结构的代码示例,请选择要使用的语言选项卡: