Verbinden mehrerer Bedingungen mit dem Lookup-Operator in MongoDB
-
Verbinden Sie mehrere Bedingungen mit dem Operator
$lookup
in MongoDB -
Erstellen Sie eine neue Sammlung und verwenden Sie die Aggregationsphase
$group
, um mehreren Bedingungen beizutreten
Heute werden wir sehen, wie man mehrere Bedingungen mit dem Operator $lookup
in MongoDB verbindet. Darüber hinaus werden wir auch einige Beispiele untersuchen, die die Verwendung der Stufe $group
und der Aggregationsstufe $unionWidth
demonstrieren.
Verbinden Sie mehrere Bedingungen mit dem Operator $lookup
in MongoDB
Wenn wir MongoDB 3.6 oder höher haben, können wir den Aggregationsoperator $lookup
pipeline
verwenden, um mehrere Bedingungen zusammenzuführen.
Dafür haben wir zwei Sammlungen namens users
und salaries
. Sie können dies auch mit den folgenden Befehlen erstellen.
Beispielcode zum Erstellen von Sammlungen:
> db.createCollection('users')
> db.createCollection('salaries')
Beispielcode zum Einfügen von Dokumenten in die 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'
}
]
)
Beispielcode zum Einfügen von Dokumenten in die Sammlung salaries
:
> db.salaries.insertMany(
[
{
username: 'userone',
salary: 3000
},
{
username: 'usertwo',
salary: 5000
}
]
)
Anzeigedaten der Sammlung users
:
> db.users.find().pretty()
AUSGANG:
{
"_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"
}
Anzeigedaten der Collection salaries
:
> db.salaries.find().pretty()
AUSGANG:
{
"_id" : ObjectId("628deb07c1e812eeeb311437"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb07c1e812eeeb311438"),
"username" : "usertwo",
"salary" : 5000
}
Nachdem wir die Sammlungen erstellt und Dokumente eingefügt haben, können wir verschiedene Szenarien untersuchen, um mehrere Bedingungen zu verbinden. Beginnen wir mit $lookup
.
Verwendung von den $lookup
-Aggregations-pipeline
-Operator
Beispielcode:
> 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()
AUSGANG:
{
"_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
}
]
}
Hier erhalten wir die Dokumente, die zwei Bedingungen erfüllen.
- Das Feld
Benutzername
ist in den Sammlungenusers
undsalaries
gleich. - Der Wert des Feldes
Gehalt
ist grösser oder gleich3000
.
Wir erhalten nur das Dokument, das beide Bedingungen erfüllt. Sie haben vielleicht bemerkt, dass das Benutzergehalt
als ein Array von Elementen sichtbar ist, wobei jedes Element ein Dokument der Sammlung salaries
ist.
Wir können die Felder $unwind
, $addFields
und $project
verwenden, um die spezifischen Felder aus beiden Sammlungen (users
und salaries
) abzurufen und ein Dokument zu bilden, wie im folgenden Beispiel gezeigt.
Beispielcode:
> 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()
AUSGANG:
{
"_id" : ObjectId("628deb40c1e812eeeb311439"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb40c1e812eeeb31143a"),
"username" : "usertwo",
"salary" : 5000
}
Der Zweck der Verwendung des Operators $unwind
besteht darin, ein Array-Feld von Eingabedokumenten in ein Ausgabedokument für jedes Element mit demselben Namen zu zerlegen.
Wenn das Array nur ein Element enthält, flacht der Stufenoperator $unwind
das Objekt ab, das das Element selbst ist. Die $addFields
verbinden das salary
-Feld von einem Objekt oder Array mit der Root-Ebene des Dokuments.
Konzentrieren wir uns auf den Grund für die Verwendung der Filterstufe $project
, bevor wir ihre Verwendung im oben angegebenen Beispiel verstehen. Wenn wir das $project
nicht verwenden, erhalten wir das salary
-Feld auf der Root-Ebene des Dokuments und das usersalary
-Objekt, was unnötig ist.
Hier verwenden wir die Filterphase $project
und geben an, welche Felder in der Ausgabe enthalten sein sollen.
Wir können die unten angegebene alternative Lösung verwenden, wenn die Projektanforderungen die Verwendung von $unwind
, $addFields
, $project
einschränken.
Beispielcode:
> 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()
AUSGANG:
{
"_id" : ObjectId("628deb07c1e812eeeb311437"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb07c1e812eeeb311438"),
"username" : "usertwo",
"salary" : 5000
}
Wir verwenden das Feld let
(optional), um die Werte von Feldern Variablen zuzuweisen. Wir greifen auf diese Variablen in der pipeline
-Phase zu, wo wir die pipeline
angeben, die auf verschiedenen Sammlungen ausgeführt werden soll.
Beachten Sie, dass wir auch die Stufe $match
verwenden, um den Auswertungsabfrageoperator namens $expr
zu nutzen, der den Wert von Feldern vergleicht.
Außerdem ist $replaceRoot
die letzte Aggregations-pipeline
-Stufe in der pipeline
, wo wir den Operator $mergeObjects
verwenden, um die $lookup
-Ausgabe mit dem Teil des $$ROOT
-Dokuments zusammenzuführen .
Wir haben nur den Operator $and
verwendet, um die Bedingungen zu verbinden. Sie können auch $or
oder beide Operatoren verwenden.
Erstellen Sie eine neue Sammlung und verwenden Sie die Aggregationsphase $group
, um mehreren Bedingungen beizutreten
Beispielcode:
> 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" }
}}
])
AUSGANG:
{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }
Für dieses Codebeispiel erstellen wir eine neue Sammlung mit dem Namen users_salaries
, führen zwei Sammlungen mit den Namen users
und salaries
zusammen und fügen diese Dokumente dann in die neu erstellte Sammlung ein. Gruppieren Sie dann nach dem Benutzernamen
, um die gewünschte Ausgabe zu erhalten.
Wir können auch die gleiche Ausgabe (wie oben angegeben) erhalten, ohne eine neue Sammlung zu erstellen. Dafür verwenden wir die Aggregationsstufe $unionWith
, die eine Vereinigung für zwei Sammlungen durchführt.
Beispielcode:
> db.users.aggregate([
{ $set: { username: "$username" } },
{ $unionWith: {
coll: "salaries",
pipeline: [{ $set: { salary: "$salary" } }]
}},
{ $group: {
_id: { username: "$username"},
"salary": { "$push": "$salary" }
}}
])
AUSGANG:
{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }