MongoDB에서 조회 연산자를 사용하여 여러 조건 조인

Mehvish Ashiq 2023년1월30일
  1. MongoDB에서 $lookup 연산자를 사용하여 여러 조건 조인
  2. 새 컬렉션을 만들고 $group 집계 단계를 사용하여 여러 조건 조인
MongoDB에서 조회 연산자를 사용하여 여러 조건 조인

오늘은 MongoDB에서 $lookup 연산자를 사용하여 여러 조건을 결합하는 방법을 알아보겠습니다. 또한 $group 단계와 $unionWidth 집계 단계의 사용을 보여주는 몇 가지 예도 살펴보겠습니다.

MongoDB에서 $lookup 연산자를 사용하여 여러 조건 조인

MongoDB 3.6 이상이 있으면 $lookup 집계 pipeline 연산자를 사용하여 여러 조건을 결합할 수 있습니다.

이를 위해 userssalaries라는 두 개의 컬렉션이 있습니다. 다음 명령을 사용하여 생성할 수도 있습니다.

컬렉션 생성을 위한 예제 코드:

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

여기에서 두 가지 조건을 충족하는 문서를 얻습니다.

  1. username 필드는 userssalaries 컬렉션에서 동일합니다.
  2. salary 필드의 값이 3000 이상입니다.

두 가지 조건을 모두 충족하는 문서만 받습니다. usersalary는 각 요소가 salaries 컬렉션의 문서인 요소의 배열로 표시된다는 것을 알 수 있습니다.

$unwind, $addFields$project를 사용하여 다음 예제와 같이 두 컬렉션(userssalaries)에서 특정 필드를 가져와 하나의 문서를 구성할 수 있습니다.

예제 코드:

> 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라는 새 컬렉션을 만들고 userssalaries라는 두 개의 컬렉션을 병합한 다음 해당 문서를 새로 만든 컬렉션에 삽입합니다. 그런 다음 사용자 이름으로 그룹화하여 원하는 출력을 얻으십시오.

새 컬렉션을 만들지 않고도 동일한 출력(위에서 제공된 대로)을 얻을 수도 있습니다. 이를 위해 두 컬렉션에 대한 통합을 수행하는 $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 ] }
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

관련 문장 - MongoDB Operator