$graphLookup (agregação)
Nesta página
Alterado na versão 3.4.
Definição
$graphLookup
Executa uma pesquisa recursiva em uma coleção, com opções para restringir a pesquisa por profundidade de recursão e filtro de consulta.
O processo de pesquisa
$graphLookup
está resumido abaixo:Documentos de entrada fluem para o estágio
$graphLookup
de uma operação de agregação.$graphLookup
direciona a pesquisa para a coleção designada pelo parâmetrofrom
(veja abaixo a lista completa de parâmetros de pesquisa).Para cada documento de entrada, a pesquisa começa com o valor designado por
startWith
.$graphLookup
corresponde ao valorstartWith
contra o campo designado porconnectToField
em outros documentos na coleçãofrom
.Para cada documento correspondente,
$graphLookup
pega o valor deconnectFromField
e verifica cada documento na coleçãofrom
em busca de um valor correspondente aconnectToField
. Para cada correspondência,$graphLookup
adiciona o documento correspondente na coleçãofrom
a um campo de array nomeado pelo parâmetroas
.Essa etapa continua recursivamente até que não haja mais documentos correspondentes encontrados, ou até que a operação atinja uma profundidade de recursão especificada pelo parâmetro
maxDepth
.$graphLookup
então acrescenta o campo de array ao documento de entrada.$graphLookup
retorna os resultados após concluir sua pesquisa em todos os documentos de entrada.
$graphLookup
tem a seguinte forma de protótipo:{ $graphLookup: { from: <collection>, startWith: <expression>, connectFromField: <string>, connectToField: <string>, as: <string>, maxDepth: <number>, depthField: <string>, restrictSearchWithMatch: <document> } } $graphLookup
obtém um documento com os seguintes campos:CampoDescriçãofrom
Coleção de destino para a operação$graphLookup
do Atlas Search, combinando recursivamente oconnectFromField
com oconnectToField
. A collectionfrom
não pode ser fragmentada e deve estar no mesmo banco de dados que qualquer outra collection usada na operação. Para obter informações, consulte Coleções fragmentadas.startWith
Expressão que especifica o valor doconnectFromField
com o qual iniciar a pesquisa recursiva. Opcionalmente,startWith
pode ser um conjunto de valores, cada um dos quais é seguido individualmente através do processo transversal.connectFromField
Nome do campo cujo valor$graphLookup
usa para corresponder recursivamente aoconnectToField
de outros documentos na coleção. Se o valor for um array, cada elemento será seguido individualmente durante o processo transversal.connectToField
Nome do campo em outros documentos para corresponder ao valor do campo especificado pelo parâmetroconnectFromField
.as
Nome do campo de array adicionado a cada documento de saída. Contém os documentos percorridos no estágio
$graphLookup
para chegar ao documento.Não é garantido que os documentos retornados no campo
as
estejam em qualquer ordem.maxDepth
Opcional. Número integral não negativo, especificando a profundidade máxima da recursão.depthField
Opcional. Nome do campo a ser adicionado a cada documento atravessado no caminho de pesquisa. O valor deste campo é a profundidade de recursão do documento, representado como umNumberLong
. O valor da profundidade de recursão começa em zero, então a primeira pesquisa corresponde à profundidade zero.restrictSearchWithMatch
Opcional. Um documento que especifica condições adicionais para a pesquisa recursiva. A sintaxe é idêntica à sintaxe do filtro de consulta.
Você não pode utilizar qualquer expressão de agregação neste filtro. Por exemplo, você não pode usar o seguinte documento para localizar documentos nos quais o valor
lastName
é diferente do valorlastName
do documento de entrada:{ lastName: { $ne: "$lastName" } } Você não pode usar o documento nesse contexto, pois
"$lastName"
agirá como uma string literal, não um caminho do campo.
Considerações
Coleções fragmentadas
A collection especificada em from
não pode ser fragmentada. No entanto, a coleção na qual você executa o método aggregate()
pode ser fragmentada. Ou seja, no seguinte:
db.collection.aggregate([ { $graphLookup: { from: "fromCollection", ... } } ])
O
collection
pode ser fragmentado.fromCollection
não pode ser fragmentado.
Para participar de várias coleções fragmentadas, considere:
Modificar os aplicativos do cliente para realizar pesquisas manuais em vez de usar o estágio de agregação
$graphLookup
.Se possível, use um modelo de dados incorporado que remova a necessidade de unir collections.
Profundidade máxima
Definir o campo maxDepth
com 0
equivale a um estágio da pesquisa $graphLookup
não recursiva.
Memória
A etapa $graphLookup
deve permanecer dentro do limite de memória de 100 megabytes. Se o allowDiskUse: true
for especificado para a operação aggregate()
, a etapa $graphLookup
ignorará a opção. Se houver outras etapas na operação do aggregate()
, a opção allowDiskUse: true
estará em vigor para estas outras etapas.
Consulte as limitações do pipeline de agregação para obter mais informações.
Visualizações e agrupamento
Se estiver realizando uma agregação que envolva várias exibições, como com $lookup
ou $graphLookup
, as exibições deverão ter o mesmo agrupamento.
Exemplos
Em uma única coleção
Uma coleção chamada employees
possui os seguintes documentos:
{ "_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" }
A seguinte operação $graphLookup
corresponde recursivamente nos campos reportsTo
e name
na coleção employees
, retornando a hierarquia de relatórios de cada pessoa:
db.employees.aggregate( [ { $graphLookup: { from: "employees", startWith: "$reportsTo", connectFromField: "reportsTo", connectToField: "name", as: "reportingHierarchy" } } ] )
A operação retorna o seguinte:
{ "_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" } ] }
A tabela a seguir fornece um caminho transversal para o documento { "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }
:
Valor inicial | O valor
| |
Profundidade 0 |
| |
Profundidade 1 |
| |
Profundidade 2 |
|
O resultado gera a hierarquia Asya -> Ron -> Eliot -> Dev
.
Em várias coleções
Como o $lookup
, o $graphLookup
pode acessar outra coleção no mesmo banco de dados.
Por exemplo, crie um banco de dados com duas coleções:
Uma coleção
airports
com os seguintes documentos:db.airports.insertMany( [ { "_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" ] } ] ) Uma coleção
travelers
com os seguintes documentos:db.travelers.insertMany( [ { "_id" : 1, "name" : "Dev", "nearestAirport" : "JFK" }, { "_id" : 2, "name" : "Eliot", "nearestAirport" : "JFK" }, { "_id" : 3, "name" : "Jeff", "nearestAirport" : "BOS" } ] )
Para cada documento na coleção travelers
, a seguinte operação de agregação procura o valor nearestAirport
na coleção airports
e recursivamente corresponde ao campo connects
ao campo airport
. A operação especifica uma profundidade máxima de recursão de 2
.
db.travelers.aggregate( [ { $graphLookup: { from: "airports", startWith: "$nearestAirport", connectFromField: "connects", connectToField: "airport", maxDepth: 2, depthField: "numConnections", as: "destinations" } } ] )
A operação retorna os seguintes resultados:
{ "_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) } ] }
A tabela a seguir fornece um caminho transversal para a pesquisa recursiva, até a profundidade 2
, onde o airport
inicial é JFK
:
Valor inicial | O valor
| ||
Profundidade 0 |
| ||
Profundidade 1 |
| ||
Profundidade 2 |
|
Com um filtro de consulta
O exemplo a seguir usa uma coleção com um conjunto
de documentos que contêm nomes de pessoas juntamente com arrayes de seus amigos
e seus hobbies. Uma operação de agregação encontra uma pessoa em particular e atravessa sua rede de conexões para encontrar pessoas que listam o golf
entre seus hobbies.
Uma coleção chamada people
contém os seguintes documentos:
{ "_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" ] }
A seguinte operação de agregação utiliza três estágios:
$match
corresponde a documentos com um camponame
contendo a string"Tanya Jordan"
. Retorna um documento de saída.$graphLookup
conecta o campofriends
do documento de saída com o camponame
de outros documentos na coleção para atravessar a rede de conexões deTanya Jordan's
Esse estágio utiliza o parâmetrorestrictSearchWithMatch
para encontrar somente documentos nos quais o arrayhobbies
contémgolf
. Retorna um documento de saída.$project
molda o documento de saída. Os nomes listados emconnections who play golf
são retirados do camponame
dos documentos listados na arraygolfers
do documento de entrada.
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" } } ] )
A operação retorna o seguinte documento:
{ "_id" : 1, "name" : "Tanya Jordan", "friends" : [ "Shirley Soto", "Terry Hawkins", "Carole Hale" ], "connections who play golf" : [ "Joseph Dennis", "Tanya Jordan", "Angelo Ward", "Carole Hale" ] }