Docs Menu
Docs Home
/ /

$graphLookup (etapa de agregación)

$graphLookup

Cambiado en la versión 5.1.

Realiza una búsqueda recursiva en una colección, con opciones para restringir la búsqueda por profundidad de recursión y filtro de query.

El proceso de búsqueda $graphLookup se resume a continuación:

  1. Los documentos de entrada fluyen a la etapa $graphLookup de una operación de agregación.

  2. $graphLookup dirige la búsqueda a la colección designada por el parámetro from (consulte a continuación la lista completa de parámetros de búsqueda).

  3. Para cada documento de entrada, la búsqueda comienza con el valor designado por startWith.

  4. $graphLookup compara el valor startWith con el campo designado por connectToField en otros documentos de la colección from.

  5. Para cada documento coincidente, $graphLookup toma el valor de connectFromField y verifica cada documento en la colección from para un valor de connectToField coincidente. Para cada coincidencia, $graphLookup agrega el documento coincidente de la colección from a un campo de arreglo nombrado por el parámetro as.

    Este paso continúa de forma recursiva hasta que no se encuentren más documentos coincidentes o hasta que la operación alcance una profundidad de recursión especificada por el parámetro maxDepth. $graphLookup luego agrega el campo del arreglo al documento de entrada. $graphLookup devuelve resultados después de completar su búsqueda en todos los documentos de entrada.

$graphLookup tiene el siguiente prototipo:

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

$graphLookup toma un documento con los siguientes campos:

Campo
Descripción

from

Colección de objetivos para el $graphLookup Operación para buscar, haciendo coincidir recursivamente connectFromField connectToFieldcon. La from colección debe estar en la misma base de datos que cualquier otra colección utilizada en la operación.

A partir de MongoDB 5.1, la colección especificada en el parámetro from puede ser fragmentada.

startWith

Expresión que especifica el valor del connectFromField con el cual iniciar la búsqueda recursiva. Si startWith se evalúa como un arreglo, $graphLookup realiza la búsqueda simultáneamente en todos los elementos del arreglo.

connectFromField

Nombre del campo cuyo valor $graphLookup se utiliza para hacer coincidir recursivamente con el connectToField de otros documentos en la colección. Si el valor es un arreglo, cada elemento se sigue individualmente a través del proceso de recorrido.

connectToField

Nombre del campo en otros documentos con el que se debe comparar el valor del campo especificado por el parámetro connectFromField.

as

Nombre del campo de arreglo añadido a cada documento de salida. Contiene los documentos que se han recorrido en la etapa $graphLookup para llegar al documento.

No se ofrecen garantías de que los documentos devueltos en el campo as estén en ningún orden específico.

maxDepth

Opcional. Número entero no negativo que especifica la profundidad máxima de recursión.

depthField

Opcional. Nombre del campo que se debe añadir a cada documento recorrido en la ruta de búsqueda. El valor de este campo es la profundidad de recursión del documento, representado como un NumberLong. El valor de la profundidad de recursión comienza en cero, por lo que la primera búsqueda corresponde a una profundidad de cero.

restrictSearchWithMatch

Opcional. Un documento que especifica condiciones adicionales para la búsqueda recursiva. La sintaxis es idéntica a la sintaxis de filtro de query.

No se puede usar ninguna expresión de agregación en este filtro. Por ejemplo, no puede utilizar el siguiente documento para encontrar documentos en los que el valor lastName sea distinto del valor lastName del documento de entrada:

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

No se puede utilizar el documento en este contexto, porque "$lastName" actuará como un literal de string, no como una ruta de campo.

A partir de MongoDB 5.1, puedes especificar sharded collections en el parámetro from de las etapas de $graphLookup.

No se puede usar la etapa $graphLookup dentro de una transacción durante el direccionamiento a una colección fragmentada.

Configurar el campo maxDepth a 0 es equivalente a una etapa de búsqueda no recursiva $graphLookup.

La etapa debe mantenerse dentro $graphLookup del 100 límite de memoria de megabytes. Si allowDiskUse: true se especifica para la aggregate() operación, la etapa ignora la opción.$graphLookup aggregate() SiallowDiskUse: true hay otras etapas en la operación, la opción se aplica a estas.

Consulte las limitaciones del pipeline de agregación para obtener más información.

La etapa $graphLookup no devuelve resultados ordenados. Para ordenar sus resultados, utilice el operador $sortArray.

Si se realiza una agregación que implique varias vistas, como con $lookup o $graphLookup, las vistas deben tener la misma intercalación.

Una colección llamada employees tiene los siguientes 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" }
] )

La siguiente operación $graphLookup coincide de forma recursiva en los campos reportsTo y name de la colección employees, devolviendo la jerarquía de reportes para cada persona:

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

La salida se asemeja a los siguientes resultados:

{
_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: 4, name: "Andrew", reportsTo: "Eliot" },
{ _id: 2, name: "Eliot", reportsTo: "Dev" },
{ _id: 1, name: "Dev" }
]
}

La siguiente tabla proporciona una ruta de acceso para el documento { "_id" : 5, "name" : "Asya", "reportsTo" : "Ron" }:

Valor inicial

El valor reportsTo del documento:

{ ... reportsTo: "Ron" }

Profundidad 0

{ _id: 3, name: "Ron", reportsTo: "Eliot" }

Profundidad 1

{ _id: 2, name: "Eliot", reportsTo: "Dev" }

Profundidad 2

{ _id: 1, name: "Dev" }

El resultado genera la jerarquía Asya -> Ron -> Eliot -> Dev.

Al igual que $lookup, $graphLookup puede acceder a otra colección en la misma base de datos.

Por ejemplo, se puede crear una base de datos con dos colecciones:

  • Una colección airports con los siguientes 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" ] }
    ] )
  • Una colección travelers con los siguientes 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 en la colección travelers, la siguiente operación de agregación busca el valor nearestAirport en la colección airports y coincide recursivamente el campo connects con el campo airport. La operación especifica una profundidad máxima de recursión de 2.

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

La salida se asemeja a los siguientes resultados:

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

La siguiente tabla proporciona una ruta de recorrido para la búsqueda recursiva, hasta la profundidad 2, donde el airport inicial es JFK:

Valor inicial

El valor nearestAirport de la colección travelers:

{ ... nearestAirport: "JFK" }

Profundidad 0

{ _id: 0, airport: "JFK", connects: [ "BOS", "ORD" ] }

Profundidad 1

{ _id: 1, airport: "BOS", connects: [ "JFK", "PWM" ] }
{ _id: 2, airport: "ORD", connects: [ "JFK" ] }

Profundidad 2

{ _id: 3, airport: "PWM", connects: [ "BOS", "LHR" ] }

El siguiente ejemplo utiliza una colección con un conjunto de documentos que contienen nombres de personas junto con arreglos de sus amigos y sus aficiones. Una operación de agregación encuentra a una persona en particular y recorre su red de conexiones para encontrar personas que incluyan golf entre sus aficiones.

Una colección llamada people contiene los siguientes 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" ]
}
] )

La siguiente operación de agregación utiliza tres etapas:

  • $match coincide en documentos con un campo name que contiene la string "Tanya Jordan". Devuelve un documento de salida.

  • $graphLookup conecta el campo friends del documento de salida con el campo name de otros documentos de la colección para recorrer la red de conexiones Tanya Jordan's. Esta etapa utiliza el parámetro restrictSearchWithMatch para encontrar solo documentos en los que el arreglo hobbies contiene golf. Devuelve un documento de salida.

  • $project da forma al documento de salida. Los nombres listados en connections who play golf se extraen del campo name de los documentos enumerados en el arreglo golfers del 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"
}
}
] )

La operación devuelve el siguiente 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"
]
}

Una colección llamada employees tiene los siguientes 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" }

La siguiente clase Employee modela los documentos en la colección employees:

public class Employee
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public Employee ReportsTo { get; set; }
public List<Employee> ReportingHierarchy { get; set; }
public List<string> Hobbies { get; set; }
}

Para usar el controlador MongoDB.NET/C# para agregar una $graphLookup etapa a una canalización de agregación, llame a GraphLookup()método en un PipelineDefinition objeto.

El siguiente ejemplo crea una etapa de pipeline que coincide recursivamente en los campos ReportsTo y Name de la colección employees, devolviendo la jerarquía de reporte para cada persona:

var pipeline = new EmptyPipelineDefinition<Employee>()
.GraphLookup<Employee, Employee, Employee, Employee, string, Employee, List<Employee>, Employee>(
from: employeeCollection,
connectFromField: e => e.ReportsTo,
connectToField: e => e.Name,
startWith: e => e.ReportsTo,
@as: e => e.ReportingHierarchy);

Se puede usar un objeto AggregateGraphLookupOptions para especificar la profundidad de recursión y el nombre del campo de profundidad. El siguiente ejemplo de código realiza la misma operación $graphLookup que el ejemplo anterior, pero especifica una profundidad máxima de recursión de 1:

var employeeCollection = client.GetDatabase("aggregation_examples").GetCollection<Employee>("employees");
var pipeline = new EmptyPipelineDefinition<Employee>()
.GraphLookup<Employee, Employee, Employee, Employee, string, Employee, List<Employee>, Employee>(
from: employeeCollection,
connectFromField: e => e.ReportsTo,
connectToField: e => e.Name,
startWith: e => e.ReportsTo,
@as: e => e.ReportingHierarchy,
new AggregateGraphLookupOptions<Employee, Employee, Employee>
{
MaxDepth = 1
});

También se puede utilizar un objeto AggregateGraphLookupOptions para especificar un filtro que los documentos deben hacer coincidir para que MongoDB los incluya en su búsqueda. El siguiente ejemplo de código realiza la misma operación $graphLookup que los ejemplos anteriores, pero solo incluye los documentos Employee en los que el campo Hobbies contiene "golf":

var employeeCollection = client.GetDatabase("aggregation_examples").GetCollection<Employee>("employees");
var pipeline = new EmptyPipelineDefinition<Employee>()
.GraphLookup<Employee, Employee, Employee, Employee, string, Employee, List<Employee>, Employee>(
from: employeeCollection,
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")
});

Una colección llamada employees tiene los siguientes 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 utilizar el controlador de MongoDB Node.js para agregar una etapa de $graphLookup a una canalización de agregación, utilice el Operador $graphLookup en un objeto de canalización.

El siguiente ejemplo crea una etapa de pipeline que hace coincidir recursivamente los campos reportsTo con los campos name en la colección employees, devolviendo la jerarquía de reportes para cada persona en un nuevo campo llamado reportingHierarchy. A continuación, el ejemplo ejecuta el pipeline de agregación:

const pipeline = [
{
$graphLookup: {
from: "employees",
connectFromField: "reportsTo",
connectToField: "name",
startWith: "$reportsTo",
as: "reportingHierarchy"
}
}
];
const cursor = collection.aggregate(pipeline);
return cursor;

Para especificar la profundidad de la recursión, se puede utilizar el campo maxDepth. El siguiente ejemplo de código realiza la misma operación $graphLookup que el anterior ejemplo, pero especifica una profundidad máxima de recursión 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 un filtro que los documentos deben cumplir para que la operación los incluya en los resultados de búsqueda, utilice el campo restrictSearchWithMatch. El siguiente ejemplo de código realiza la misma operación $graphLookup que los ejemplos anteriores, pero solo incluye los documentos employee en los que el campo hobbies contiene "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;

Para aprender más sobre cómo utilizar $graphLookup, consulte el seminario web: Trabajando con datos de grafos en MongoDB.

Volver

$geoNear

En esta página