MongoDB es una popular base de datos NoSQL que almacena datos en colecciones. Las colecciones de MongoDB se componen de uno o más documentos que contienen los datos reales en formato JSON. Los documentos son comparables a las filas de las bases de datos relacionales SQL tradicionales, mientras que las colecciones son análogas a las tablas.

Una funcionalidad clave en las bases de datos es la capacidad de consultar los datos almacenados en la base. La consulta de datos permite la recuperación de información específica, el análisis de datos, la elaboración de informes de datos y también la integración de datos.

Para poder consultar una base de datos de forma eficaz, es crucial poder combinar datos de varias tablas, en el caso de las bases de datos SQL o de varias colecciones en las bases de datos NOSQL, en un único conjunto de resultados.

En MongoDB $lookup permite a los usuarios combinar información de dos colecciones al realizar una consulta. Realiza el equivalente a una unión externa izquierda en una base de datos SQL.

uso y objetivo de $lookup

Una función importante de las bases de datos es el procesamiento de datos para obtener información significativa a partir de datos sin procesar.

Por ejemplo, si dirige un negocio de restauración, es posible que desee analizar los datos de su restaurante para averiguar cuánto gana cada día, qué comidas se demandan los fines de semana o incluso averiguar cuántas tazas de café vende a cada hora del día.

Para tales necesidades, las simples consultas a la base de datos no serán suficientes. Necesita realizar consultas avanzadas sobre los datos que tiene almacenados. Para dar respuesta a estas necesidades, MongoDB cuenta con una función denominada canalización de agregación.

Una canalización de agregación es un sistema formado por operaciones componibles denominadas etapas, que se utilizan para procesar datos con el fin de producir un resultado agregado final. Algunos ejemplos de etapas en la canalización de agregación son $sort, $match, $group, $merge, $count y $lookup, entre otras.

Estas etapas pueden aplicarse en cualquier orden en una canalización de agregación. En cada etapa de una canalización de agregación, se realizan diferentes operaciones sobre los datos que pasan por la canalización de agregación.

leftOuterJoin

así,$lookup es una etapa en la canalización de agregación de MongoDB. $Lookup se utiliza para realizar una unión externa izquierda entre dos colecciones en una base de datos MongoDB. Una unión exterior izquierda combina todos los documentos o entradas de la izquierda con documentos o entradas coincidentes de la derecha.

Por ejemplo, considere las dos colecciones siguientes, que se han representado en formato tabular para facilitar su comprensión:

colección_pedidos:

pedido_idcustomer_idfecha_pedidoimporte_total
11002022-05-0150.00
21012022-05-0275.00
31022022-05-03100.00

colección_clientes:

numero_clientenombre_clientecorreo_clienteteléfono_cliente
100Juan Pérezjohn@example.com555-1234
102Jane Smithjane@example.com555-5678

Si realizamos una unión externa izquierda en las colecciones anteriores utilizando el campo customer_id, que aparece en la colección order_collection, siendo la colección order_collection la colección izquierda y la colección customers_collection la colección derecha, el resultado contendrá todos los documentos de la colección orders y los documentos de la colección customers que tengan un customer_num que coincida con un customer_id de cualquiera de los registros de la colección orders.

El resultado final de la operación de unión externa izquierda en las colecciones de pedidos y clientes tiene el siguiente aspecto cuando se representa en formato tabular:

join

Observe que para el cliente con customer_id 101 en la colección Pedidos, que no tenía un valor customer_num coincidente en la colección Clientes, los valores correspondientes que faltaban en la tabla de clientes se han rellenado con null.

$lookup realiza una comparación de igualdad estricta entre los campos y recupera todo el documento coincidente, y no sólo los campos coincidentes.

sintaxis de $lookup

La sintaxis de $lookup es la siguiente:

{
   $lookup
     {
       from: <colección a unir>,
       localField: <campo de los documentos de entrada>,
       foreignField: <campo de los documentos de la colección "from">,
       as: <campo de la matriz de salida&gt
     }
}

$lookup tiene cuatro parámetros

  • from – representa la colección de la que queremos buscar los documentos. En nuestro ejemplo anterior utilizando orders_collection y customers_collection, pondríamos customers_collection como from de la colección.
  • localField – es un campo de la colección de trabajo o primaria que utilizamos para comparar con los campos de nuestra colección from(customers_collection en nuestro caso). En el ejemplo anterior, el localField sería customer_id que se encuentra en la colección orders_collection.
  • foreignField – es el campo con el que queremos comparar en la colección que especificamos en from. En nuestro ejemplo, sería customer_num que se encuentra en la colección customer_collection y que utilizamos como valor en from
  • as – se trata de un nuevo nombre de campo que especificamos para representar el campo que aparecerá en nuestro documento, que contiene los documentos resultantes de las coincidencias entre el localField y el foreignField. Todas estas coincidencias se colocan en una matriz en este campo. Si no hay coincidencias, este campo contendrá una matriz vacía.

A partir de nuestras dos colecciones anteriores, utilizaríamos el siguiente código para realizar una operación $lookup en las dos colecciones con la colección pedidos_como nuestra colección de trabajo o primaria.

{
    $lookup: {
      from: "colección_clientes",
      localField: "customer_id",
      foreignField: "numero_cliente",
      as: "customer_info"
 }

Tenga en cuenta que el campo as puede ser cualquier valor de cadena. Sin embargo, si le da un nombre que ya existe en el documento de trabajo, ese campo se sobrescribirá.

Unir datos de varias colecciones

MongoDB $lookup es una etapa útil en una canalización de agregación en MongoDB. Aunque no es un requisito que una canalización de agregación en MongoDB deba tener una etapa $lookup , la etapa es crucial cuando se realizan consultas complejas que requieren unir datos de múltiples colecciones.

La etapa $lookup realiza una unión exterior izquierda en dos colecciones que tiene como resultado la creación de un nuevo campo o la sobreescritura de los valores de un campo existente con una matriz que contiene documentos de otra colección.

Estos documentos se seleccionan en función de si tienen valores que coinciden con los del campo con el que se comparan. El resultado final es un campo que contiene una matriz de documentos en caso de que se hayan encontrado coincidencias o una matriz vacía en caso de que no se hayan encontrado coincidencias.

Consideremos las colecciones de empleados y proyectos que se muestran a continuación.

Screenshot-from-2023-05-11-11-10-07

Podemos utilizar el código siguiente para unir las dos colecciones:

db.projects.aggregate([
   {
      búsqueda: {
         from: "empleados",
         localField: "empleados",
         foreignField: "_id",
         as: "empleados_asignados"
      }
   }
])

El resultado de esta operación es una combinación de las dos colecciones. El resultado son los proyectos y todos los empleados asignados a cada proyecto. Los empleados se representan en un array.

Screenshot-from-2023-05-11-11-12-53

Etapas del pipeline que pueden utilizarse junto con $lookup

Como ya se ha mencionado, $lookup es una etapa de una canalización de agregación de MongoDB, y puede utilizarse junto con otras etapas de canalización de agregación. Para mostrar cómo pueden utilizarse estas etapas junto con $lookup, utilizaremos las dos colecciones siguientes con fines ilustrativos.

collection

En MongoDB, se almacenan en formato JSON. Este es el aspecto de las colecciones anteriores en MongoDB.

Screenshot-from-2023-05-11-10-14-11

Algunos ejemplos de etapas de canalización de agregación que se pueden utilizar junto con $lookup incluyen:

$match

$match es una etapa de canalización de agregación que se utiliza para filtrar el flujo de documentos y permitir que sólo aquellos documentos que cumplan la condición dada pasen a la siguiente etapa de la canalización de agregación. Esta etapa se utiliza mejor al principio de la canalización para eliminar los documentos que no se van a necesitar y optimizar así la canalización de agregación.

Utilizando las dos colecciones anteriores, puede combinar $match y $lookup de la siguiente manera

db.users.aggregate([
   {
      $match {
         país: "USA"
      }
   },
   {
      búsqueda: {
         from: "pedidos",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   }
])

$match se utiliza para filtrar los usuarios de EE.UU.. A continuación, el resultado de $match se combina con $lookup para obtener los detalles de los pedidos de los usuarios de EE.UU.. El resultado de la operación anterior se muestra a continuación:

Screenshot-from-2023-05-11-10-24-04

$proyecto

$project es una etapa utilizada para remodelar documentos especificando qué campos incluir, excluir o añadir a los documentos. Por ejemplo, en caso de que esté procesando documentos con diez campos cada uno, pero sólo cuatro campos de los documentos contienen datos que necesita para su procesamiento de datos, puede utilizar $project para filtrar fuera los campos que no necesita.

Esto le permite evitar el envío de datos innecesarios a la siguiente etapa de su canalización de agregación.

Podemos combinar $lookup y $project de la siguiente manera

db.users.aggregate([
   {
      $búsqueda: {
         from: "pedidos",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   },
   {
      $proyecto: {
         nombre: 1,
         _id: 0,
         total_gastado: { $suma: "$pedidos.precio" }
      }
   }
])

Lo anterior combina las colecciones de usuarios y pedidos utilizando $lookup, luego $project se utiliza para mostrar sólo el nombre de cada usuario y la cantidad gastada por cada usuario. $project también se utiliza para eliminar el campo _id de los resultados. El resultado de la operación anterior se muestra a continuación:

Screenshot-from-2023-05-11-10-34-57

$unwind

$unwind es una etapa de agregación que se utiliza para deconstruir o desenrollar un campo de matriz creando nuevos documentos para cada elemento de la matriz. Esto es útil en caso de que desee ejecutar alguna agregación sobre los valores del campo del array.

Por ejemplo, en el ejemplo siguiente, en caso de que quiera ejecutar una agregación sobre el campo aficiones, no podrá hacerlo porque se trata de un array. Sin embargo, puede desenrollarlo utilizando $unwind y luego realizar agregaciones sobre los documentos resultantes.

unWind

Utilizando las colecciones users y orders, podemos utilizar $lookup y $unwind conjuntamente de la siguiente manera

db.users.aggregate([
   {
      $lookup: {
         from: "pedidos",
         localField: "_id",
         foreignField: "user_id",
         as: "orders"
      }
   },
   {
      $despidos "$pedidos"
   }
])

En el código anterior, $lookup devuelve un campo array llamado pedidos. a continuación se utiliza $unwind para desenrollar el campo de matriz. El resultado de esta operación se muestra a continuación: Observe que Alice aparece dos veces porque tenía dos pedidos.

Screenshot-from-2023-05-11-10-41-52

Ejemplos de casos de uso de $lookup

Al realizar el procesamiento de datos, $lookup es una herramienta útil. Por ejemplo, puede tener dos colecciones que desee unir basándose en campos de las colecciones que tengan datos similares. Para ello puede utilizar una simple etapa $lookup y añadir un nuevo campo en las colecciones primarias, que contienen documentos obtenidos de otra colección.

Considere las colecciones usuarios y pedidos que se muestran a continuación:

Screenshot-from-2023-05-11-10-14-11

Las dos colecciones pueden combinarse utilizando $lookup para obtener el resultado que se muestra a continuación:

Screenshot-from-2023-05-11-11-43-05

$lookup también puede utilizarse para realizar uniones más complejas. $lookup no se limita a realizar uniones en dos colecciones. Puede implementar múltiples etapas $lookup para realizar uniones en más de dos colecciones. Considere las tres colecciones que se muestran a continuación:

Screenshot-from-2023-05-11-11-55-37

Podemos utilizar el código siguiente para realizar una unión más compleja a través de las tres colecciones para obtener todos los pedidos que se realizaron y también los detalles de los productos que se pidieron.

El código siguiente nos permite hacer precisamente eso:

db.orders.aggregate([
   {
      búsqueda: {
         from: "articulos_pedido",
         localField: "_id",
         foreignField: "order_id",
         as: "order_items"
      }
   },
   {
      $descargar "$artículos_pedido"
   },
   {
      $buscar: {
         de: "productos",
         localField: "order_items.product_id",
         foreignField: "_id",
         as: "product_details"
      }
   },
   {
      $grupo {
         _id: "$_id",
         cliente: { $primero: "$cliente" },
         total: { $suma: "$artículos_pedido.precio" },
         productos: { $push: "$detalles_producto" }
      }
   }
])

El resultado de la operación anterior se muestra a continuación:

Screenshot-from-2023-05-11-12-02-17

Conclusión

Cuando se realiza un procesamiento de datos que implica múltiples colecciones, $lookup puede ser útil ya que le permite unir datos y sacar conclusiones basadas en datos almacenados en múltiples colecciones. El procesamiento de datos rara vez se basa en una sola colección.

Para extraer conclusiones significativas de los datos, unir datos de varias colecciones es un paso clave. Por lo tanto, considere la posibilidad de utilizar la etapa $lookup en su canalización de agregación de MongoDB para permitirle procesar mejor sus datos y extraer conclusiones significativas de los datos brutos almacenados en varias colecciones.

También puede explorar algunos comandos y consultas de MongoDB.