Joindre plusieurs conditions à l'aide de l'opérateur Lookup dans MongoDB

Mehvish Ashiq 30 janvier 2023
  1. Joindre plusieurs conditions à l’aide de l’opérateur $lookup dans MongoDB
  2. Créer une nouvelle collection et utiliser l’étape d’agrégation $group pour joindre plusieurs conditions
Joindre plusieurs conditions à l'aide de l'opérateur Lookup dans MongoDB

Aujourd’hui, nous allons voir comment joindre plusieurs conditions en utilisant l’opérateur $lookup dans MongoDB. De plus, nous explorerons également quelques exemples démontrant l’utilisation de l’étape $group et de l’étape d’agrégation $unionWidth.

Joindre plusieurs conditions à l’aide de l’opérateur $lookup dans MongoDB

Si nous avons MongoDB 3.6 ou supérieur, nous pouvons utiliser l’opérateur pipeline d’agrégation $lookup pour joindre plusieurs conditions.

Pour cela, nous avons deux collections nommées users et salaries. Vous pouvez également le créer à l’aide des commandes suivantes.

Exemple de code pour créer des collections :

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

Exemple de code pour insérer des documents dans la collection 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'
        }
    ]
)

Exemple de code pour l’insertion de documents dans la collection salaries :

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

Données d’affichage de la collection users :

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

PRODUCTION:

{
        "_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"
}

Données d’affichage de la collection salaries :

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

PRODUCTION:

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

Après avoir créé les collections et inséré des documents, nous pouvons explorer différents scénarios pour joindre plusieurs conditions. Commençons par $lookup.

Utiliser l’opérateur pipeline d’agrégation $lookup

Exemple de code :

> 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()

PRODUCTION:

{
        "_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
                }
        ]
}

Ici, on obtient les documents remplissant deux conditions.

  1. Le champ username est le même dans les collections users et salaries.
  2. La valeur du champ salaire est supérieure ou égale à 3000.

Nous n’obtenons que le document remplissant les deux conditions. Vous avez peut-être remarqué que le usersalary est visible sous la forme d’un tableau d’éléments où chaque élément est un document de la collection salaries.

Nous pouvons utiliser $unwind, $addFields et $project pour obtenir les champs spécifiques des deux collections (users et salaries) et former un seul document, comme le montre l’exemple suivant.

Exemple de code :

> 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()

PRODUCTION:

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

Le but de l’utilisation de l’opérateur $unwind est de déconstruire un champ de tableau des documents d’entrée vers le document de sortie pour chaque élément portant le même nom.

S’il n’y a qu’un seul élément dans le tableau, alors l’opérateur de scène $unwind aplatit l’objet, qui est l’élément lui-même. Le champ $addFields joint le champ salary d’un objet ou d’un tableau au niveau racine du document.

Concentrons-nous sur la raison d’être de l’étape de filtrage $project avant de comprendre son utilisation dans l’exemple ci-dessus. Si nous n’utilisons pas le $project, nous obtiendrons le champ salary à la racine du document et l’objet usersalary, ce qui est inutile.

C’est ici que nous utilisons l’étape de filtre $project et spécifions quels champs doivent figurer dans la sortie.

Nous pouvons utiliser la solution alternative donnée ci-dessous si les exigences du projet limitent l’utilisation de $unwind, $addFields, $project.

Exemple de code :

> 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()

PRODUCTION:

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

On utilise le champ let (optionnel) pour affecter les valeurs des champs aux variables. Nous accédons à ces variables dans l’étape pipeline, où nous spécifions le pipeline à exécuter sur différentes collections.

Notez que nous utilisons également l’étape $match pour tirer parti de l’opérateur de requête d’évaluation nommé $expr, qui compare la valeur des champs.

De plus, $replaceRoot est la dernière étape pipeline d’agrégation dans le pipeline où nous utilisons l’opérateur $mergeObjects pour fusionner la sortie $lookup avec la partie du document $$ROOT.

Nous avons utilisé uniquement l’opérateur $and pour joindre les conditions. Vous pouvez également utiliser $or ou les deux opérateurs.

Créer une nouvelle collection et utiliser l’étape d’agrégation $group pour joindre plusieurs conditions

Exemple de code :

> 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" }
    }}
])

PRODUCTION:

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

Pour cet exemple de code, nous créons une nouvelle collection nommée users_salaries, fusionnons deux collections nommées users et salaries, puis insérons ces documents dans la collection nouvellement créée. Ensuite, on regroupe par le username pour obtenir le résultat souhaité.

Nous pouvons également obtenir la même sortie (comme indiqué ci-dessus) sans créer de nouvelle collection. Pour cela, nous utilisons l’étape d’agrégation $unionWith, qui réalise une union pour deux collections.

Exemple de code :

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

PRODUCTION:

{ "_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

Article connexe - MongoDB Operator