Unir múltiples condiciones usando el operador Lookup en MongoDB

Mehvish Ashiq 30 enero 2023
  1. Unir múltiples condiciones usando el operador $lookup en MongoDB
  2. Cree una nueva colección y use la etapa de agregación $group para unir múltiples condiciones
Unir múltiples condiciones usando el operador Lookup en MongoDB

Hoy veremos cómo unir múltiples condiciones usando el operador $lookup en MongoDB. Además, también exploraremos algunos ejemplos que demuestran el uso de la etapa $group y la etapa de agregación $unionWidth.

Unir múltiples condiciones usando el operador $lookup en MongoDB

Si tenemos MongoDB 3.6 o superior, podemos usar el operador de agregación $lookup pipeline para unir múltiples condiciones.

Para ello disponemos de dos colecciones denominadas users y salaries. También puede crear eso usando los siguientes comandos.

Código de ejemplo para crear colecciones:

> db.createCollection('users')
> db.createCollection('salaries')

Ejemplo de Código para Insertar Documentos en la Colección users:

> db.users.insertMany(
    [
        {
            username: 'userone',
            age: 30,
            gender: 'Female',
            city: 'Lahore',
            country: 'Pakistan'
        },
        {
            username: 'usertwo',
            age: 35,
            gender: 'Male',
            city: 'Florida',
            country: 'United States'
        }
    ]
)

Ejemplo de Código para Inserción de Documentos en el Cobro salaries:

> db.salaries.insertMany(
    [
        {
            username: 'userone',
            salary: 3000
        },
        {
            username: 'usertwo',
            salary: 5000
        }
    ]
)

Mostrar Datos de la Colección users:

> db.users.find().pretty()

Producción :

{
        "_id" : ObjectId("628deb40c1e812eeeb311439"),
        "username" : "userone",
        "age" : 30,
        "gender" : "Female",
        "city" : "Lahore",
        "country" : "Pakistan"
}
{
        "_id" : ObjectId("628deb40c1e812eeeb31143a"),
        "username" : "usertwo",
        "age" : 35,
        "gender" : "Male",
        "city" : "Florida",
        "country" : "United States"
}

Mostrar Datos de la Colección salaries:

> db.salaries.find().pretty()

Producción :

{
        "_id" : ObjectId("628deb07c1e812eeeb311437"),
        "username" : "userone",
        "salary" : 3000
}
{
        "_id" : ObjectId("628deb07c1e812eeeb311438"),
        "username" : "usertwo",
        "salary" : 5000
}

Después de crear las colecciones e insertar documentos, podemos explorar varios escenarios para unir múltiples condiciones. Empecemos con $lookup.

Use el operador de agregación $lookup pipeline

Código de ejemplo:

> db.users.aggregate([
    {
        $lookup: {
            from: 'salaries',
            let: {
                user_name: '$username',
                user_salary: 3000
            },
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $eq: ['$username', '$$user_name'] },
                            { $gte: ['$salary','$$user_salary'] }
                        ]
                    }
                }
           }],
           as: 'usersalary'
        }
    }
]).pretty()

Producción :

{
        "_id" : ObjectId("628deb40c1e812eeeb311439"),
        "username" : "userone",
        "age" : 30,
        "gender" : "Female",
        "city" : "Lahore",
        "country" : "Pakistan",
        "usersalary" : [
                {
                        "_id" : ObjectId("628deb07c1e812eeeb311437"),
                        "username" : "userone",
                        "salary" : 3000
                }
        ]
}
{
        "_id" : ObjectId("628deb40c1e812eeeb31143a"),
        "username" : "usertwo",
        "age" : 35,
        "gender" : "Male",
        "city" : "Florida",
        "country" : "United States",
        "usersalary" : [
                {
                        "_id" : ObjectId("628deb07c1e812eeeb311438"),
                        "username" : "usertwo",
                        "salary" : 5000
                }
        ]
}

Aquí, obtenemos los documentos que cumplen dos condiciones.

  1. El campo nombre de usuario es el mismo en las colecciones users y salaries.
  2. El valor del campo salario es mayor o igual a 3000.

Solo obtenemos el documento que cumple ambas condiciones. Es posible que haya notado que el campo usersalary es visible como una matriz de elementos donde cada elemento es un documento de la colección salaries.

Podemos usar $unwind, $addFields y $project para obtener los campos específicos de ambas colecciones (users y salaries) y formar un documento, como se demuestra en el siguiente ejemplo.

Código de ejemplo:

> db.users.aggregate([
    {
        $lookup: {
            from: 'salaries',
            let: {
                user_name: '$username',
                user_salary: 3000
            },
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $eq: ['$username', '$$user_name'] },
                            { $gte: ['$salary','$$user_salary'] }
                        ]
                    }
                }
           }],
           as: 'usersalary'
        }
    },
    {
        $unwind:'$usersalary'
    },
    {
        $addFields: {
            salary: '$usersalary.salary'
        }
    },
    {
       $project: {
           username: 1,
           salary: 1
       }
    }
]).pretty()

Producción :

{
        "_id" : ObjectId("628deb40c1e812eeeb311439"),
        "username" : "userone",
        "salary" : 3000
}
{
        "_id" : ObjectId("628deb40c1e812eeeb31143a"),
        "username" : "usertwo",
        "salary" : 5000
}

El propósito de utilizar el operador $unwind es deconstruir un campo de matriz desde los documentos de entrada hasta el documento de salida para cada elemento con el mismo nombre.

Si solo hay un elemento en la matriz, entonces el operador de etapa $unwind aplana el objeto, que es el elemento mismo. El $addFields une el campo salary de un objeto o matriz al nivel raíz del documento.

Centrémonos en la razón para usar la etapa de filtro $project antes de entender su uso en el ejemplo anterior. Si no usamos el $project, obtendremos el campo salario en el nivel raíz del documento y el objeto usersalary, que no es necesario.

Aquí es donde usamos la etapa de filtro $project y especificamos qué campos deben estar en la salida.

Podemos usar la solución alternativa que se proporciona a continuación si los requisitos del proyecto restringen el uso de $unwind, $addFields, $project.

Código de ejemplo:

> db.users.aggregate([
    {
        $lookup: {
            from: 'salaries',
            let: {
                user_name: '$username',
                user_salary: 3000
            },
            pipeline: [{
                $match: {
                    $expr: {
                        $and: [
                            { $eq: ['$username', '$$user_name'] },
                            { $gte: ['$salary','$$user_salary'] }
                        ]
                    }
                }
           }],
           as: 'usersalary'
        }
    },
       {
          $replaceRoot: {
             newRoot: {
                $mergeObjects:[
                   {
                      $arrayElemAt: [
                         "$usersalary", 0
                      ]
                   },
                   {
                      salary: "$$ROOT.salary"
                   }
                ]
             }
          }
       }
    ]
).pretty()

Producción :

{
        "_id" : ObjectId("628deb07c1e812eeeb311437"),
        "username" : "userone",
        "salary" : 3000
}
{
        "_id" : ObjectId("628deb07c1e812eeeb311438"),
        "username" : "usertwo",
        "salary" : 5000
}

Usamos el campo let (opcional) para asignar los valores de los campos a las variables. Accedemos a estas variables en la etapa de pipeline, donde especificamos la pipeline para que se ejecute en diferentes colecciones.

Tenga en cuenta que también estamos utilizando la etapa $match para aprovechar el operador de consulta de evaluación llamado $expr, que compara el valor de los campos.

Además, $replaceRoot es la última etapa de agregación de la pipeline en la que utilizamos el operador $mergeObjects para fusionar la salida $lookup con la parte del documento $$ROOT .

Usamos solo el operador $and para unir las condiciones. También puede usar $or o ambos operadores.

Cree una nueva colección y use la etapa de agregación $group para unir múltiples condiciones

Código de ejemplo:

> db.users_salaries.insertMany(
    db.users.find({}, {"_id": 0})
    .toArray()
    .concat(db.salaries.find({}, {"_id": 0}).toArray())
)

db.users_salaries.aggregate([
    { "$group": {
        "_id": { "username": "$username" },
        "salary": { "$push": "$salary" }
    }}
])

Producción :

{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }

Para este ejemplo de código, creamos una nueva colección llamada users_salaries, fusionamos dos colecciones llamadas users y salaries, y luego insertamos esos documentos en la colección recién creada. Luego, agrupe por el nombre de usuario para obtener el resultado deseado.

También podemos obtener el mismo resultado (como se indicó anteriormente) sin crear una nueva colección. Para eso, usamos la etapa de agregación $unionWith, que realiza una unión para dos colecciones.

Código de ejemplo:

> db.users.aggregate([
  { $set: { username: "$username" } },
  { $unionWith: {
    coll: "salaries",
    pipeline: [{ $set: { salary: "$salary" } }]
  }},
  { $group: {
    _id: { username: "$username"},
     "salary": { "$push": "$salary" }
  }}
])

Producción :

{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

Artículo relacionado - MongoDB Operator