Joindre plusieurs conditions à l'aide de l'opérateur Lookup dans MongoDB
-
Joindre plusieurs conditions à l’aide de l’opérateur
$lookup
dans MongoDB -
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](/img/MongoDB/feature-image---mongodb-lookup-multiple-fields.webp)
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.
- Le champ
username
est le même dans les collectionsusers
etsalaries
. - 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 ] }