MongoDB에서 조회 연산자를 사용하여 여러 조건 조인
오늘은 MongoDB에서 $lookup
연산자를 사용하여 여러 조건을 결합하는 방법을 알아보겠습니다. 또한 $group
단계와 $unionWidth
집계 단계의 사용을 보여주는 몇 가지 예도 살펴보겠습니다.
MongoDB에서 $lookup
연산자를 사용하여 여러 조건 조인
MongoDB 3.6 이상이 있으면 $lookup
집계 pipeline
연산자를 사용하여 여러 조건을 결합할 수 있습니다.
이를 위해 users
와 salaries
라는 두 개의 컬렉션이 있습니다. 다음 명령을 사용하여 생성할 수도 있습니다.
컬렉션 생성을 위한 예제 코드:
> db.createCollection('users')
> db.createCollection('salaries')
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'
}
]
)
salaries
컬렉션에 문서를 삽입하기 위한 예제 코드:
> db.salaries.insertMany(
[
{
username: 'userone',
salary: 3000
},
{
username: 'usertwo',
salary: 5000
}
]
)
users
컬렉션의 데이터 표시:
> db.users.find().pretty()
출력:
{
"_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"
}
급여
컬렉션의 데이터 표시:
> db.salaries.find().pretty()
출력:
{
"_id" : ObjectId("628deb07c1e812eeeb311437"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb07c1e812eeeb311438"),
"username" : "usertwo",
"salary" : 5000
}
컬렉션을 만들고 문서를 삽입한 후 여러 조건을 결합하는 다양한 시나리오를 탐색할 수 있습니다. $lookup
부터 시작하겠습니다.
$lookup
집계 pipeline
연산자 사용
예제 코드:
> 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()
출력:
{
"_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
}
]
}
여기에서 두 가지 조건을 충족하는 문서를 얻습니다.
username
필드는users
및salaries
컬렉션에서 동일합니다.salary
필드의 값이3000
이상입니다.
두 가지 조건을 모두 충족하는 문서만 받습니다. usersalary
는 각 요소가 salaries
컬렉션의 문서인 요소의 배열로 표시된다는 것을 알 수 있습니다.
$unwind
, $addFields
및 $project
를 사용하여 다음 예제와 같이 두 컬렉션(users
및 salaries
)에서 특정 필드를 가져와 하나의 문서를 구성할 수 있습니다.
예제 코드:
> 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()
출력:
{
"_id" : ObjectId("628deb40c1e812eeeb311439"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb40c1e812eeeb31143a"),
"username" : "usertwo",
"salary" : 5000
}
$unwind
연산자를 사용하는 목적은 동일한 이름을 가진 모든 요소에 대해 입력 문서에서 출력 하나의 문서로 배열 필드를 분해하는 것입니다.
배열에 요소가 하나만 있는 경우 $unwind
단계 연산자는 요소 자체인 개체를 평면화합니다. $addFields
는 개체 또는 배열의 salary
필드를 문서의 루트 수준으로 조인합니다.
위의 예에서 사용을 이해하기 전에 $project
필터 단계를 사용하는 이유에 초점을 맞추겠습니다. $project
를 사용하지 않으면 문서의 루트 수준에서 salary
필드와 usersalary
개체를 가져오게 되며 이는 필요하지 않습니다.
여기에서 $project
필터 단계를 사용하고 출력에 있어야 하는 필드를 지정합니다.
프로젝트 요구 사항이 $unwind
, $addFields
, $project
사용을 제한하는 경우 아래에 제공된 대체 솔루션을 사용할 수 있습니다.
예제 코드:
> 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()
출력:
{
"_id" : ObjectId("628deb07c1e812eeeb311437"),
"username" : "userone",
"salary" : 3000
}
{
"_id" : ObjectId("628deb07c1e812eeeb311438"),
"username" : "usertwo",
"salary" : 5000
}
let
필드(선택 사항)를 사용하여 필드 값을 변수에 할당합니다. pipeline
단계에서 이러한 변수에 액세스합니다. 여기서 pipeline
을 지정하여 다른 컬렉션에서 실행됩니다.
또한 $match
단계를 사용하여 필드 값을 비교하는 $expr
이라는 평가 쿼리 연산자를 활용하고 있습니다.
또한 $replaceRoot
는 $lookup
출력을 $$ROOT
문서 부분과 병합하기 위해 $mergeObjects
연산자를 사용하는 pipeline
의 마지막 집계 pipeline
단계입니다. .
조건을 결합하기 위해 $and
연산자만 사용했습니다. $or
또는 두 연산자를 모두 사용할 수도 있습니다.
새 컬렉션을 만들고 $group
집계 단계를 사용하여 여러 조건 조인
예제 코드:
> 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" }
}}
])
출력:
{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }
이 코드 예제에서는 users_salaries
라는 새 컬렉션을 만들고 users
와 salaries
라는 두 개의 컬렉션을 병합한 다음 해당 문서를 새로 만든 컬렉션에 삽입합니다. 그런 다음 사용자 이름
으로 그룹화하여 원하는 출력을 얻으십시오.
새 컬렉션을 만들지 않고도 동일한 출력(위에서 제공된 대로)을 얻을 수도 있습니다. 이를 위해 두 컬렉션에 대한 통합을 수행하는 $unionWith
집계 단계를 사용합니다.
예제 코드:
> db.users.aggregate([
{ $set: { username: "$username" } },
{ $unionWith: {
coll: "salaries",
pipeline: [{ $set: { salary: "$salary" } }]
}},
{ $group: {
_id: { username: "$username"},
"salary": { "$push": "$salary" }
}}
])
출력:
{ "_id" : { "username" : "userone" }, "salary" : [ 3000 ] }
{ "_id" : { "username" : "usertwo" }, "salary" : [ 5000 ] }