MongoDB の lookup 演算子を使用して複数の条件に参加する

Mehvish Ashiq 2023年1月30日
  1. MongoDB の $lookup 演算子を使用して複数の条件に参加する
  2. 新しいコレクションを作成し、$group 集約ステージを使用して複数の条件に参加する
MongoDB の lookup 演算子を使用して複数の条件に参加する

今日は、MongoDB の $lookup 演算子を使用して複数の条件を結合する方法を説明します。さらに、$group ステージと $unionWidth 集約ステージの使用法を示すいくつかの例についても説明します。

MongoDB の $lookup 演算子を使用して複数の条件に参加する

MongoDB 3.6 以降を使用している場合は、$lookup 集計 pipeline 演算子を使用して複数の条件を結合できます。

このために、userssalaries という名前の 2つのコレクションがあります。次のコマンドを使用して作成することもできます。

コレクションを作成するためのサンプルコード:

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

salaries コレクションの表示データ:

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

出力:

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

コレクションを作成してドキュメントを挿入した後、さまざまなシナリオを調べて複数の条件を結合できます。 $lookup から始めましょう。

$lookup 集約パイプライン演算子を使用する

サンプルコード:

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

ここでは、2つの条件を満たすドキュメントを取得します。

  1. username フィールドは、users コレクションと salaries コレクションで同じです。
  2. salary フィールドの値が 3000 以上です。

両方の条件を満たすドキュメントのみを取得します。usersalary が要素の配列として表示され、各要素が salaries コレクションのドキュメントであることに気付いたかもしれません。

次の例に示すように、$unwind$addFields、および $project を使用して、両方のコレクション(userssalaries)から特定のフィールドを取得し、1つのドキュメントを形成できます。

サンプルコード:

> 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 演算子を使用する目的は、同じ名前の要素ごとに、入力ドキュメントから出力 1 ドキュメントへの配列フィールドを分解することです。

配列に要素が 1つしかない場合、$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 は、pipeline の最後の集約 pipeline ステージであり、$mergeObjects 演算子を使用して、$lookup 出力を $$ROOT ドキュメントの部分とマージします。。

条件を結合するために $and 演算子のみを使用しました。 $または または両方の演算子を使用することもできます。

新しいコレクションを作成し、$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 という名前の 2つのコレクションをマージしてから、それらのドキュメントを新しく作成したコレクションに挿入します。次に、ユーザー名でグループ化して、目的の出力を取得します。

新しいコレクションを作成せずに、(上記のように)同じ出力を取得することもできます。そのために、2つのコレクションの結合を実行する $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
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