$graphLookup (aggregation)

在本页面

在版本 3.4 中更改。

Definition

$graphLookup搜索过程总结如下:

此步骤以递归方式 continue 进行,直到找不到更多匹配的文档,或者直到操作达到maxDepth参数指定的递归深度为止。然后$graphLookup将数组字段追加到 Importing 文档中。 $graphLookup完成对所有 Importing 文档的搜索后返回结果。

$graphLookup具有以下原型形式:

{
   $graphLookup: {
      from: <collection>,
      startWith: <expression>,
      connectFromField: <string>,
      connectToField: <string>,
      as: <string>,
      maxDepth: <number>,
      depthField: <string>,
      restrictSearchWithMatch: <document>
   }
}

$graphLookup接收包含以下字段的文档:

Field Description
from $graphLookup操作要搜索的目标集合,将connectFromFieldconnectToField递归匹配。不能对from集合进行分片,并且必须与该操作中使用的任何其他集合位于同一数据库中。有关信息,请参见Sharded Collections
startWith Expression指定用于开始递归搜索的connectFromField的值。可选地,startWith可以是值的数组,每个值都分别经过遍历过程。
connectFromField $graphLookup用于与集合中其他文档的connectToField递归匹配的字段名称。如果值是数组,则每个元素都将分别经过遍历过程。
connectToField 其他文档中与connectFromField参数指定的字段值相匹配的字段名。
as 添加到每个输出文档中的数组字段的名称。包含在$graphLookup阶段遍历的文档。


Note





不能保证在as字段中返回的文档以任何 Sequences 排列。



|
| maxDepth | *可选.*非负整数,指定最大递归深度。
| depthField | *可选.*要添加到搜索路径中每个已遍历文档的字段名称。该字段的值是文档的递归深度,表示为NumberLong。递归深度值从零开始,因此第一次查找对应于零深度。
| restrictSearchWithMatch | *可选.*为递归搜索指定其他条件的文档。语法与query filter语法相同。

> [!NOTE|label:Note]




您不能在此过滤器中使用任何aggregation expression。例如,查询文档如





{ lastName: { $ne: "$lastName" } }





在这种情况下将无法找到lastName值与 Importing 文档的lastName值不同的文档,因为"$lastName"将充当字符串 Literals,而不是字段路径。



|

Considerations

Sharded Collections

from中指定的集合不能为sharded。但是,可以对运行aggregate()方法的集合进行分片。也就是说,在下面:

db.collection.aggregate([
   { $graphLookup: { from: "fromCollection", ... } }
])

要加入多个分片集合,请考虑:

Max Depth

maxDepth字段设置为0等效于非递归$graphLookup搜索阶段。

Memory

$graphLookup阶段必须保持在 100 MiB 内存限制内。如果为aggregate()操作指定了allowDiskUse: true,则$graphLookup阶段将忽略该选项。如果在aggregate()操作中还有其他观察allowDiskUse: true的阶段,则allowDiskUse: true选项对这些其他阶段有效。

有关更多信息,请参见聚集管线限制

视图和排序规则

如果执行涉及多个视图的聚合(例如$lookup$graphLookup),则这些视图必须具有相同的collation

Examples

在一个集合内

名为employees的集合具有以下文档:

{ "_id" : 1, "name" : "Dev" }
{ "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
{ "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
{ "_id" : 4, "name" : "Andrew", "reportsTo" : "Eliot" }
{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }
{ "_id" : 6, "name" : "Dan", "reportsTo" : "Andrew" }

以下$graphLookup操作在employees集合中的reportsToname字段上递归匹配,返回每个人的报告层次结构:

db.employees.aggregate( [
   {
      $graphLookup: {
         from: "employees",
         startWith: "$reportsTo",
         connectFromField: "reportsTo",
         connectToField: "name",
         as: "reportingHierarchy"
      }
   }
] )

该操作返回以下内容:

{
   "_id" : 1,
   "name" : "Dev",
   "reportingHierarchy" : [ ]
}
{
   "_id" : 2,
   "name" : "Eliot",
   "reportsTo" : "Dev",
   "reportingHierarchy" : [
      { "_id" : 1, "name" : "Dev" }
   ]
}
{
   "_id" : 3,
   "name" : "Ron",
   "reportsTo" : "Eliot",
   "reportingHierarchy" : [
      { "_id" : 1, "name" : "Dev" },
      { "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
   ]
}
{
   "_id" : 4,
   "name" : "Andrew",
   "reportsTo" : "Eliot",
   "reportingHierarchy" : [
      { "_id" : 1, "name" : "Dev" },
      { "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
   ]
}
{
   "_id" : 5,
   "name" : "Asya",
   "reportsTo" : "Ron",
   "reportingHierarchy" : [
      { "_id" : 1, "name" : "Dev" },
      { "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" },
      { "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
   ]
}
{
   "_id" : 6,
   "name" : "Dan",
   "reportsTo" : "Andrew",
   "reportingHierarchy" : [
      { "_id" : 1, "name" : "Dev" },
      { "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" },
      { "_id" : 4, "name" : "Andrew", "reportsTo" : "Eliot" }
   ]
}

下表提供了文档{ "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }的遍历路径:

起始值 文档的reportsTo值:
{ ... "reportsTo" : "Ron" }
Depth 0 { "_id" : 3, "name" : "Ron", "reportsTo" : "Eliot" }
Depth 1 { "_id" : 2, "name" : "Eliot", "reportsTo" : "Dev" }
Depth 2 { "_id" : 1, "name" : "Dev" }

输出生成层次结构Asya -> Ron -> Eliot -> Dev

跨多个收藏集

$lookup一样,$graphLookup可以访问同一数据库中的另一个集合。

在以下示例中,数据库包含两个集合:

{ "_id" : 0, "airport" : "JFK", "connects" : [ "BOS", "ORD" ] }
{ "_id" : 1, "airport" : "BOS", "connects" : [ "JFK", "PWM" ] }
{ "_id" : 2, "airport" : "ORD", "connects" : [ "JFK" ] }
{ "_id" : 3, "airport" : "PWM", "connects" : [ "BOS", "LHR" ] }
{ "_id" : 4, "airport" : "LHR", "connects" : [ "PWM" ] }
{ "_id" : 1, "name" : "Dev", "nearestAirport" : "JFK" }
{ "_id" : 2, "name" : "Eliot", "nearestAirport" : "JFK" }
{ "_id" : 3, "name" : "Jeff", "nearestAirport" : "BOS" }

对于travelers集合中的每个文档,以下聚合操作将查找airports集合中的nearestAirport值,并将connects字段与airport字段递归匹配。该操作将最大递归深度指定为2

db.travelers.aggregate( [
   {
      $graphLookup: {
         from: "airports",
         startWith: "$nearestAirport",
         connectFromField: "connects",
         connectToField: "airport",
         maxDepth: 2,
         depthField: "numConnections",
         as: "destinations"
      }
   }
] )

该操作返回以下结果:

{
   "_id" : 1,
   "name" : "Dev",
   "nearestAirport" : "JFK",
   "destinations" : [
      { "_id" : 3,
        "airport" : "PWM",
        "connects" : [ "BOS", "LHR" ],
        "numConnections" : NumberLong(2) },
      { "_id" : 2,
        "airport" : "ORD",
        "connects" : [ "JFK" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 1,
        "airport" : "BOS",
        "connects" : [ "JFK", "PWM" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 0,
        "airport" : "JFK",
        "connects" : [ "BOS", "ORD" ],
        "numConnections" : NumberLong(0) }
   ]
}
{
   "_id" : 2,
   "name" : "Eliot",
   "nearestAirport" : "JFK",
   "destinations" : [
      { "_id" : 3,
        "airport" : "PWM",
        "connects" : [ "BOS", "LHR" ],
        "numConnections" : NumberLong(2) },
      { "_id" : 2,
        "airport" : "ORD",
        "connects" : [ "JFK" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 1,
        "airport" : "BOS",
        "connects" : [ "JFK", "PWM" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 0,
        "airport" : "JFK",
        "connects" : [ "BOS", "ORD" ],
        "numConnections" : NumberLong(0) } ]
}
{
   "_id" : 3,
   "name" : "Jeff",
   "nearestAirport" : "BOS",
   "destinations" : [
      { "_id" : 2,
        "airport" : "ORD",
        "connects" : [ "JFK" ],
        "numConnections" : NumberLong(2) },
      { "_id" : 3,
        "airport" : "PWM",
        "connects" : [ "BOS", "LHR" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 4,
        "airport" : "LHR",
        "connects" : [ "PWM" ],
        "numConnections" : NumberLong(2) },
      { "_id" : 0,
        "airport" : "JFK",
        "connects" : [ "BOS", "ORD" ],
        "numConnections" : NumberLong(1) },
      { "_id" : 1,
        "airport" : "BOS",
        "connects" : [ "JFK", "PWM" ],
        "numConnections" : NumberLong(0) }
   ]
}

下表提供了递归搜索的遍历路径,深度为2,起始airportJFK

起始值 来自travelers集合的nearestAirport值:
{ ... "nearestAirport" : "JFK" }
Depth 0 { "_id" : 0, "airport" : "JFK", "connects" : [ "BOS", "ORD" ] }
Depth 1 { "_id" : 1, "airport" : "BOS", "connects" : [ "JFK", "PWM"] }
{ "_id" : 2, "airport" : "ORD", "connects" : [ "JFK"] }
Depth 2 { "_id" : 3, "airport" : "PWM", "connects" : [ "BOS", "LHR" ] }

使用查询过滤器

下面的示例使用一个集合,该集合包含一组文档,其中包含人的名字以及他们的朋友和爱好的数组。聚集操作找到一个特定的人,并遍历她的联系网络,以找到在他们的兴趣中列出golf的人。

名为people的集合包含以下文档:

{
  "_id" : 1,
  "name" : "Tanya Jordan",
  "friends" : [ "Shirley Soto", "Terry Hawkins", "Carole Hale" ],
  "hobbies" : [ "tennis", "unicycling", "golf" ]
}
{
  "_id" : 2,
  "name" : "Carole Hale",
  "friends" : [ "Joseph Dennis", "Tanya Jordan", "Terry Hawkins" ],
  "hobbies" : [ "archery", "golf", "woodworking" ]
}
{
  "_id" : 3,
  "name" : "Terry Hawkins",
  "friends" : [ "Tanya Jordan", "Carole Hale", "Angelo Ward" ],
  "hobbies" : [ "knitting", "frisbee" ]
}
{
  "_id" : 4,
  "name" : "Joseph Dennis",
  "friends" : [ "Angelo Ward", "Carole Hale" ],
  "hobbies" : [ "tennis", "golf", "topiary" ]
}
{
  "_id" : 5,
  "name" : "Angelo Ward",
  "friends" : [ "Terry Hawkins", "Shirley Soto", "Joseph Dennis" ],
  "hobbies" : [ "travel", "ceramics", "golf" ]
}
{
   "_id" : 6,
   "name" : "Shirley Soto",
   "friends" : [ "Angelo Ward", "Tanya Jordan", "Carole Hale" ],
   "hobbies" : [ "frisbee", "set theory" ]
 }

以下聚合操作分为三个阶段:

db.people.aggregate( [
  { $match: { "name": "Tanya Jordan" } },
  { $graphLookup: {
      from: "people",
      startWith: "$friends",
      connectFromField: "friends",
      connectToField: "name",
      as: "golfers",
      restrictSearchWithMatch: { "hobbies" : "golf" }
    }
  },
  { $project: {
      "name": 1,
      "friends": 1,
      "connections who play golf": "$golfers.name"
    }
  }
] )

该操作返回以下文档:

{
   "_id" : 1,
   "name" : "Tanya Jordan",
   "friends" : [
      "Shirley Soto",
      "Terry Hawkins",
      "Carole Hale"
   ],
   "connections who play golf" : [
      "Joseph Dennis",
      "Tanya Jordan",
      "Angelo Ward",
      "Carole Hale"
   ]
}

Additional Resource

网络研讨会:在 MongoDB 中使用图数据

首页