Definição
$graphLookupAlterado na versão 5.1.
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
$graphLookupestá resumido abaixo:Documentos de entrada fluem para o estágio
$graphLookupde uma operação de agregação.$graphLookupdireciona 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.$graphLookupcorresponde ao valorstartWithcontra o campo designado porconnectToFieldem outros documentos na coleçãofrom.Para cada documento correspondente,
$graphLookuppega o valor deconnectFromFielde verifica cada documento na coleçãofromem busca de um valor correspondente aconnectToField. Para cada correspondência,$graphLookupadiciona o documento correspondente na coleçãofroma 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.$graphLookupentão acrescenta o campo de array ao documento de entrada.$graphLookupretorna os resultados após concluir sua pesquisa em todos os documentos de entrada.
$graphLookuptem a seguinte forma de protótipo:{ $graphLookup: { from: <collection>, startWith: <expression>, connectFromField: <string>, connectToField: <string>, as: <string>, maxDepth: <number>, depthField: <string>, restrictSearchWithMatch: <document> } } $graphLookupobtém um documento com os seguintes campos:CampoDescriçãofromColeção de destino para a operação
$graphLookupa ser pesquisada, combinando recursivamente oconnectFromFieldcom oconnectToField. A coleçãofromdeve estar no mesmo banco de dados que quaisquer outras coleções utilizadas na operação.Para suporte de fragmentação, consulte Coleções Fragmentadas.
startWithExpressão que especifica o valor do
connectFromFieldcom o qual iniciar a pesquisa recursiva. SestartWithavaliar para uma array,$graphLookupexecuta a pesquisa simultaneamente a partir de todos os elementos da array.connectFromFieldNome do campo cujo valor usa para corresponder recursivamente
$graphLookupaoconnectToFieldde outros documentos na coleção. Se o valor for uma matriz, cada elemento será seguido individualmente durante o processo transversal.connectToFieldNome do campo em outros documentos para corresponder ao valor do campo especificado pelo parâmetro
connectFromField.asNome do campo de array adicionado a cada documento de saída. Contém os documentos percorridos no estágio para chegar ao
$graphLookupdocumento.Não é garantido que os documentos retornados no campo
asestejam em qualquer ordem.maxDepthOpcional. Número integral não negativo, especificando a profundidade máxima da recursão.
depthFieldOpcional. 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 um
NumberLong. O valor da profundidade de recursão começa em zero, então a primeira pesquisa corresponde à profundidade zero.restrictSearchWithMatchOpcional. 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 valorlastNamedo documento de entrada:{ lastName: { $ne: "$lastName" } } Você não pode usar o documento neste contexto, porque
"$lastName"atuará como uma string literalmente, e não como um caminho do campo.
Considerações
Coleções fragmentadas
A partir do MongoDB,5.1 você pode especificar collections fragmentadas no from parâmetro de $graphLookup estágios.
Você não pode usar a etapa $graphLookup dentro de uma transação enquanto segmenta uma coleção fragmentada.
Profundidade máxima
Definir o maxDepth campo como 0 é equivalente a um estágio de pesquisa não recursivo.$graphLookup
Memória
Se o estágio$graphLookupconsumir mais de 100 megabytes de memória, ele gravará automaticamente arquivos temporários em disco. Você pode ver quando$graphLookupusa o disco por meio do comandoserverStatuse exibir uma explicação do$graphLookupuso do disco por meio do comandoexplain()no modo de detalhamentoexecutionStats.
Se o estágio $graphLookup exceder 100 megabytes de memória e a allowDiskUse opção estiver definida false como, retornará um$graphLookup erro.
Consulte limites do pipeline de agregação para obter mais informações.
Resultados não ordenados
O estágio $graphLookup não retorna resultados ordenados. Para classificar seus resultados, use o $sortArray operador.
Visualizações e agrupamento
Se estiver realizando uma agregação que envolva várias exibições, como com ou, as exibições deverão ter o $lookup $graphLookupmesmo agrupamento.
Exemplos
Em uma única coleção
Uma coleção chamada employees possui os seguintes documentos:
db.employees.insertMany( [ { _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 corresponde $graphLookup recursivamente reportsTo name em e campos na employees coleção, retornando a hierarquia de relatórios para cada pessoa:
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: 2, name: 'Eliot', reportsTo: 'Dev' }, { _id: 1, name: 'Dev' } ] }, { _id: 4, name: 'Andrew', reportsTo: 'Eliot', reportingHierarchy: [ { _id: 2, name: 'Eliot', reportsTo: 'Dev' }, { _id: 1, name: 'Dev' } ] }, { _id: 5, name: 'Asya', reportsTo: 'Ron', reportingHierarchy: [ { _id: 2, name: 'Eliot', reportsTo: 'Dev' }, { _id: 3, name: 'Ron', reportsTo: 'Eliot' }, { _id: 1, name: 'Dev' } ] }, { _id: 6, name: 'Dan', reportsTo: 'Andrew', reportingHierarchy: [ { _id: 2, name: 'Eliot', reportsTo: 'Dev' }, { _id: 1, name: '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 $lookup o, o pode acessar outra coleção no mesmo banco de$graphLookup dados.
Por exemplo, crie um banco de dados com duas coleções:
Uma coleção
airportscom 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
travelerscom 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" } } ] )
[ { _id: 1, name: 'Dev', nearestAirport: 'JFK', destinations: [ { _id: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('0') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('1') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('2') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('1') } ] }, { _id: 2, name: 'Eliot', nearestAirport: 'JFK', destinations: [ { _id: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('0') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('1') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('2') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('1') } ] }, { _id: 3, name: 'Jeff', nearestAirport: 'BOS', destinations: [ { _id: 0, airport: 'JFK', connects: [ 'BOS', 'ORD' ], numConnections: Long('1') }, { _id: 1, airport: 'BOS', connects: [ 'JFK', 'PWM' ], numConnections: Long('0') }, { _id: 4, airport: 'LHR', connects: [ 'PWM' ], numConnections: Long('2') }, { _id: 3, airport: 'PWM', connects: [ 'BOS', 'LHR' ], numConnections: Long('1') }, { _id: 2, airport: 'ORD', connects: [ 'JFK' ], numConnections: Long('2') } ] } ]
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:
db.people.insertMany( [ { _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:
$matchcorresponde a documentos com um camponamecontendo a string"Tanya Jordan". Retorna um output document.$graphLookupconecta o campo do documento de saídafriendscom onamecampo de outros documentos na coleção para atravessarTanya Jordan'srede de conexões. Esse estágio usa orestrictSearchWithMatchparâmetro para encontrar somente documentos nos quais ahobbiesmatrizgolfcontém. Retorna um documento de saída .$projectmolda o documento de saída. Os nomes listados emconnections who play golfsão retirados do camponamedos documentos listados na arraygolfersdo 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" } } ] )
[ { _id: 1, name: 'Tanya Jordan', friends: [ 'Shirley Soto', 'Terry Hawkins', 'Carole Hale' ], 'connections who play golf': [ 'Tanya Jordan', 'Joseph Dennis', 'Angelo Ward', 'Carole Hale' ] } ]
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" }
Os seguintes documentos de modelos de classe Employee na coleção employees:
[] public class Employee { [] public int Id { get; set; } [] public string Name { get; set; } = null!; [] public string? ReportsTo { get; set; } [] public List<string> Hobbies { get; set; } = new(); [] public List<Employee> ReportingHierarchy { get; set; } = new(); }
Para usar o driver MongoDB .NET/C# para adicionar um $graphLookup estágio a uma agregação pipeline, chame o método unionWith() em um PipelineDefinition objeto.
O exemplo a seguir cria um estágio de pipeline que corresponde recursivamente aos campos ReportsTo e Name na collection employees, retornando a hierarquia de relatórios para cada pessoa:
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy);
Você pode usar um objeto AggregateGraphLookupOptions para especificar a profundidade da recursão e o nome do campo de profundidade. O exemplo de código a seguir executa a mesma $graphLookup operação do exemplo anterior , mas especifica uma profundidade máxima de recursão 1 de:
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy, new AggregateGraphLookupOptions<Employee, Employee, Employee> { MaxDepth = 1 });
Você também pode usar um objeto AggregateGraphLookupOptions para especificar um filtro ao qual os documentos devem corresponder para que o MongoDB os inclua em sua pesquisa. O exemplo de código a seguir executa a mesma operação $graphLookup dos exemplos anteriores, mas inclui somente documentos Employee em que o campo Hobbies contém "golf":
var pipeline = new EmptyPipelineDefinition<Employee>() .GraphLookup<Employee, Employee, Employee, string, string, string, List<Employee>, Employee>( from: _collection, connectFromField: e => e.ReportsTo!, connectToField: e => e.Name, startWith: e => e.ReportsTo!, @as: e => e.ReportingHierarchy, new AggregateGraphLookupOptions<Employee, Employee, Employee> { MaxDepth = 1, RestrictSearchWithMatch = Builders<Employee>.Filter.AnyEq( e => e.Hobbies, "golf") });
Uma coleção chamada employees possui os seguintes documentos:
db.employees.insertMany([ { _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" } ]);
Para usar o driver Node.js do MongoDB para adicionar um estágio $graphLookup a um pipeline de agregação , use o operador $graphLookup em um objeto de pipeline.
O exemplo a seguir cria um estágio de pipeline que combina recursivamente os campos reportsTo aos campos name na coleção employees, retornando a hierarquia de relatórios para cada pessoa em um novo campo chamado reportingHierarchy. O exemplo em seguida executa o pipeline de agregação:
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Para especificar a profundidade da recursão, utilize o campo maxDepth. O exemplo de código a seguir realiza a mesma operação $graphLookup que o exemplo anterior, mas define uma profundidade máxima de recursão de 1:
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy", maxDepth: 1 } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Para especificar um filtro que os documentos devem corresponder para que a operação os inclua nos resultados da pesquisa, use o campo restrictSearchWithMatch. O exemplo de código a seguir realiza a mesma operação $graphLookup que os exemplos anteriores, mas inclui apenas os documentos employee em que o campo hobbies contém "golf":
const pipeline = [ { $graphLookup: { from: "employees", connectFromField: "reportsTo", connectToField: "name", startWith: "$reportsTo", as: "reportingHierarchy", maxDepth: 1, restrictSearchWithMatch: { hobbies: "golf" } } } ]; const cursor = collection.aggregate(pipeline); return cursor;
Saiba mais
Para saber mais sobre como usar o,$graphLookup consulte Trabalhar com Dados de Gráfico no MongoDB.