No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Aprendemos a usar $lookup

14/21
Recursos

¿Cómo manejar relaciones en MongoDB usando lockup?

MongoDB es frecuentemente catalogado como limitado en cuanto a la gestión de uniones, porque no maneja las relaciones entre tablas de manera nativa, como lo hacen las bases de datos relacionales. Sin embargo, el operador lockup viene al rescate. Este operador permite unir colecciones en MongoDB, haciendo posible el manejo de datos interrelacionados con la misma facilidad que en bases de datos relacionales. Te explicaré cómo puedes lograrlo y cómo puedes usar estas uniones para obtener análisis profundos de tus datos, específicamente generando una lista de clientes con más transacciones.

¿Qué base de datos utilizamos y cuál es su estructura?

En esta explicación, consideraremos una base de datos distinta a la usada anteriormente. Usaremos una base de datos que contiene información sobre compras y transacciones de una tienda. La estructura está dividida en tres colecciones:

  1. Clientes: Guarda información sobre los clientes, como su nombre y correo.
  2. Cuentas: Almacena los datos de las cuentas adquiridas por los clientes.
  3. Transacciones: Contiene el historial de transacciones realizadas en la tienda.

Nos enfocaremos en obtener los clientes con el mayor número de transacciones, mostrando su nombre y la cantidad total de transacciones que realizaron.

¿Cómo se aplican las uniones en MongoDB?

La unión de colecciones en MongoDB se lleva a cabo en la pestaña de 'aggregations' a través de una serie de pasos organizados en un pipeline. A continuación, desglosamos cómo se realiza:

Primer paso: Usando lockup para la primera unión

El primer paso es realizar una unión utilizando lockup entre la colección de cuentas y la de clientes. Este es el código en MongoDB:

db.accounts.aggregate([
  {
    $lookup: {
      from: "clients",
      localField: "accountID",
      foreignField: "accountID",
      as: "account_info"
    }
  }
])

Asegúrate de tener un campo común entre ambas colecciones para hacer la relación, en este caso, accountID.

Segundo paso: Desenrollar arrays

Después de una unión con lockup, los resultados se devuelven en un array. Necesitamos desenrollar este array para acceder a los documentos individuales mediante el operador $unwind:

{
  $unwind: "$account_info"
}

Tercer paso: Segunda unión con lockup

Repetimos el proceso para unir las transacciones con la información de cuentas. Aquí especificamos nuevamente los campos necesarios y cómo queremos que se nombre esta segunda unión:

{
  $lookup: {
    from: "transactions",
    localField: "account_info.accountID",
    foreignField: "accountID",
    as: "account_transactions"
  }
}

Cuarto paso: Desenrollar el segundo array

De nuevo aplicamos $unwind para acceder a los detalles de las transacciones:

{
  $unwind: "$account_transactions"
}

¿Cómo se obtiene el top de clientes con más transacciones?

Tras unir las colecciones necesarias, utilizamos el operador $group para agrupar los datos por cliente, obtener la cuenta total de transacciones, y finalmente ordenarlos para poder identificar los clientes más activos.

Agrupación de clientes por número de transacciones

El operador $group ayuda a reunir datos basados en un criterio en común. En este caso, agrupamos por el nombre del cliente y acumulamos la información sobre sus transacciones:

{
  $group: {
    _id: "$account_info.clientName",
    total_transactions: { $sum: 1 }
  }
}

Orden y límite de resultados

Luego, ordenamos a los clientes en base al número total de transacciones en orden descendente para identificar aquellos más activos, y limitamos el resultado para obtener sólo los mejores cinco clientes:

{
  $sort: { total_transactions: -1 }
},
{
  $limit: 5
}

Proyección final de resultados

Finalmente, usamos $project para formatear cómo queremos que se presenten los resultados, enfocándonos en el nombre del cliente y el total de transacciones:

{
  $project: {
    _id: 0,
    clientName: "$_id",
    total_transactions: 1
  }
}

¡Y eso es todo! Ahora tienes una lista ordenada con los cinco clientes que más han transaccionado en tu tienda. Esta metodología, aunque robusta, evidencia la flexibilidad y el poder de MongoDB cuando se requieren uniones complejas y análisis avanzado de datos.

Aportes 6

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

En mi opinión el ejercicio está más interesante realmente y podríamos platearlo con lo siguiente, no sería correcto ponerle nombre únicamente, porque el servicio de compra se rige por el id de la cuenta y más de una persona se puede llamar igual, en segundo termino el los documentos embebidos de transacciones algunos puntos son venta y otros son compras (y también considerar si el universo de datos están el mismo periodo de compras, o discriminar este parámetro si consideramos qué son los históricos), tendríamos que discriminar una de otras, y por ultimo no es lo mismo cantidad de transacciones a monto, entonces, podría ser un poco más específico el problema acotando el alcance de la consulta. Tomando en cuenta eso podríamos hacer la consulta más interesante. Por lo pronto comparto mi propuesta acotada a lo que se menciona en la clase. ```js use("sample_analytics") // db.listingsAndReviews.createIndex({ "address.location": "2dsphere" }); db.getCollection("customers").aggregate([ //Desde customers estoy haciendo traer la información de accounts //En este primer lookup estamos creando un array que nos permite trabajar {$lookup: { //Especificamos de que colección estamos partiendo from: "accounts", //Indica el campo local de la primera colección localField: "accounts", foreignField: "account_id", as: "account_info" //este es el array creado }}, //Extraemos la información del array {$unwind:"$account_info"}, //Ahora tenemos juntos información de costumers y account //Se junta más información con transactions {$lookup: { //Especificamos de que colección estamos partiendo from: "transactions", //Indica el campo local de la primera colección localField: "account_info.account_id", foreignField: "account_id", as: "transactions_inf" //este es el array creado }}, //Extraemos la información del array {$unwind:"$transactions_inf"}, {$sort:{ "transactions_inf.transaction_count": -1 }}, {$project: { "_id": 0, "Cliente": "$name", "Número de transacciones": "$transactions_inf.transaction_count" }}, {$limit: 5} ]) ```use("sample\_analytics")// db.listingsAndReviews.createIndex({ "address.location": "2dsphere" }); db.getCollection("customers").aggregate(\[     //Desde customers estoy haciendo traer la información de accounts    //En este primer lookup estamos creando un array que nos permite trabajar    {$lookup: {      //Especificamos de que colección estamos partiendo      from: "accounts",      //Indica el campo local de la primera colección      localField: "accounts",          foreignField: "account\_id",      as: "account\_info" //este es el array creado    }},    //Extraemos la información del array    {$unwind:"$account\_info"},        //Ahora tenemos juntos información de costumers y account    //Se junta más información con transactions    {$lookup: {        //Especificamos de que colección estamos partiendo        from: "transactions",        //Indica el campo local de la primera colección        localField: "account\_info.account\_id",            foreignField: "account\_id",        as: "transactions\_inf" //este es el array creado      }},      //Extraemos la información del array    {$unwind:"$transactions\_inf"},    {$sort:{      "transactions\_inf.transaction\_count": -1    }},    {$project: {       "\_id": 0,       "Cliente": "$name",       "Número de transacciones": "$transactions\_inf.transaction\_count"    }},    {$limit: 5}])
Logré resolver el ejercicio, repasando las notas que he tomado a lo largo del curso y mirando la documentación de MongoDB. Después de ensayar varias veces lo logré. Comparto el código documentando el paso a paso. ![](https://static.platzi.com/media/user_upload/ejerciciolookup-afedee32-98e6-4f8a-a241-0455f0a7e7ed.jpg) **Resultado:** ```js Nombre Cliente: "Ashley Rodriguez" Cantidad de Transacciones: 471 Nombre Cliente: "John Williams" Cantidad de Transacciones: 443 Nombre Cliente: "Phillip Obrien" Cantidad de Transacciones: 421 Nombre Cliente: "Travis White" Cantidad de Transacciones: 409 Nombre Cliente: "Robert Pearson" Cantidad de Transacciones: 408 ```Nunca paren de aprender 🚀.
Un ejemplo usando fútbol: ```js // obtener los equipos con mas goles use("football") db.teams.aggregate([ { $lookup:{ from: "scorers", localField: "name", foreignField: "equipo", as: "Goleadores" } }, { $unwind: "$Goleadores" }, { $group: { _id: "$name", totalGoles: { $sum: "$Goleadores.goles" } } }, { $sort: {totalGoles: -1} }, { $project: { _id: 0, Equipo: "$_id", totalGoles: 1 } } ]) ```![](https://static.platzi.com/media/user_upload/image-8cec8f9d-f87e-44f2-970a-e92d79dce5db.jpg)
Comparto mi salida al reto:        $group: {            \_id: {                "client\_id": "$\_id",                "client\_name": "$name"            },            conteo\_transacciones: {                $sum: "$transactions\_info.transaction\_count"            }            // conteo\_transacciones: {            //     $sum: {            //         $size: "$transactions\_info.transactions"            //     }            // }        }    }, ![](https://static.platzi.com/media/user_upload/image-063476f7-7f79-429f-a17c-5b0da0ee88f6.jpg) En mi caso decidí agrupar por el customer id y el customer name, dado que pueden presentarse casos de clientes distintos que se llamen igual. Para el conteo de transacciones, no apliqué un size al array de las transacciones asociadas a una determinada account, sino que decidí tomar el atributo ya calculado que se encontraba en la colección de transacciones llamado transaction\_count con lo cual se logra el mismo resultado que con el size, pero en temas de performance de la consulta podría ser mejor al tomar atributos ya calculados. ```js { $group: { _id: { "client_id": "$_id", "client_name": "$name" }, conteo_transacciones: { $sum: "$transactions_info.transaction_count" } } }, ```
//realizar uniones con otras colecciones
// listar los clientes que tienen la mayor cantidad de transacciones
[
  {
    $lookup: {
      from: "accounts", // coleccion de donde se parte
      localField: "accounts", //campo de la coleccion customers
      foreignField: "account_id", // cacmpo a relacionar de la coleccion customers a la coleccion account
      as: "account_info"  //array donde se alamacena la informacion
    }
  },
  // para trabajar el array resultado del primer resultado
  {
    $unwind: "$account_info"  
  },
  {
    $lookup: {
      from: "transactions",
      localField: "account_info.account_id",
      foreignField: "account_id",
      as: "account_transactions"
    }
  },
  {
    $unwind: "$account_transactions"
  },
  {
    $group:{
      _id: "$name",
      totalCompras:{
        $sum:{
          $size: "$account_transactions.transactions"
        }
      }
    }
  },
  {
    $sort:{
      totalCompras: -1
    }
  },
    {
      $limit:5
    },
  {
    $project:{
      _id:0,
      Nombre: "$_id",
      totalCompras: 1
    }
  } 
]
use('sample_analytics')

db.customers.aggregate([
  {
    $lookup: {
      from: "accounts",
      localField: "accounts",
      foreignField: "account_id",
      as: "account_info"
    }
  },
  {
    $unwind: "$account_info"
  },
  {
    $lookup: {
      from: "transactions",
      localField: "account_info.account_id",
      foreignField: "account_id",
      as: "account_trasactions"
    }
  },
  {
    $unwind: "$account_trasactions"
  },
  {
    $group: {
      _id: "$name",
      total: {
        $sum: {
          $size: "$account_trasactions.transactions"
        }
      }
    }
  },
  {
    $sort: {
      total: -1
    }
  },
  {
    $limit: 5
  }
])