$lookup(集計)
項目一覧
定義
$lookup
バージョン8.0で変更。
同じデータベース内のコレクションへの左外部結合を実行して 、"join" コレクションのドキュメントをフィルタリングして処理します。
$lookup
ステージでは、各入力ドキュメントに新しい配列フィールドが追加されます。 新しい配列フィールドには、結合済みコレクションと一致するドキュメントが含まれます。$lookup
ステージは、これらを再作成したドキュメントを次のステージに渡します。MongoDB 5.1以降では、シャーディングされたコレクションで
$lookup
を使用できます。2 つの異なるコレクションの要素を結合するには、
$unionWith
パイプライン ステージを使用します。
互換性
次の環境でホストされる配置には $lookup
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
$lookup
ステージには、次のセクションに示す構文のバリエーションがあります。
1 つの結合条件による等価一致
入力ドキュメントのフィールドと「結合された」コレクションのドキュメントのフィールドとの間で等価一致を実行するには、$lookup
ステージで次の構文を使用します。
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, as: <output array field> } }
$lookup
は次のフィールドを持つドキュメントを取得します。
フィールド | 説明 |
---|---|
結合を実行する同じデータベース内のコレクションを指定します。
MongoDB 5.1 以降では、 | |
入力ドキュメントに追加する新しい配列フィールドの名前を指定します。新しい配列フィールドには、 |
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, ( SELECT ARRAY_AGG(*) FROM <collection to join> WHERE <foreignField> = <collection.localField> ) AS <output array field> FROM collection;
注意
このページの SQL ステートメントは、MongoDB 集計パイプライン構文の比較に含まれています。SQL ステートメントは実行できません。
MongoDB の例については、次のページを参照してください。
結合されたコレクションの結合条件とサブクエリ
MongoDB は以下をサポートします。
結合したコレクションでパイプラインを実行する。
複数の結合条件。
相関サブクエリと非相関サブクエリ。
MongoDB では、相関サブクエリは、結合されたコレクションのドキュメント フィールドを参照する $lookup
ステージの パイプライン です。非相関サブクエリでは、結合されたフィールドは参照されません。
注意
MongoDB5.0 以降では、$lookup
$sample
ステージ、$sampleRate
演算子、または$rand
演算子を含む、 パイプライン ステージ内の相関のないサブクエリの場合、繰り返される場合はサブクエリが常に再度実行されます。以前は、サブクエリの出力サイズに応じて、サブクエリの出力がキャッシュされるか、サブクエリが再度実行されていました。
MongoDB 相関サブクエリは、内部クエリが外部クエリ値を参照する SQL 相関サブクエリに相当します。SQL 非相関サブクエリは、外部クエリ値を参照しません。
MongoDB 5.0 は簡潔な相関サブクエリもサポートしています。
2 つのコレクションに対して相関サブクエリと非相関サブクエリを実行し、単一の等価一致以外の結合条件を実行するには、次の$lookup
構文を使用します。
{ $lookup: { from: <joined collection>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run on joined collection> ], as: <output array field> } }
$lookup
ステージは、次のフィールドを持つドキュメントを受け入れます。
フィールド | 説明 |
---|---|
結合操作を実行する同じデータベース内のコレクションを指定します。
MongoDB 5.1 以降では、 | |
任意。パイプラインステージで使用する変数を指定します。変数式を使用して、 パイプラインステージで変数を参照するには、 let
| |
結合済みコレクションで実行する には
パイプラインステージで変数を参照するには、 let
| |
結合済みドキュメントに追加する新しい配列フィールドの名前を指定します。新しい配列フィールドには、結合済みコレクションと一致するドキュメントが含まれます。指定した名前がすでに結合済みドキュメントに存在する場合、既存のフィールドは上書きされます。 |
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, <output array field> FROM collection WHERE <output array field> IN ( SELECT <documents as determined from the pipeline> FROM <collection to join> WHERE <pipeline> );
次の例を参照してください。
簡潔な構文を使用した相関サブクエリ
バージョン 5.0 で追加
MongoDB 5.0 以降、相関サブクエリに構文を使えるようになりました。相関サブクエリは、結合済みの「外部」コレクションと、aggregate()
メソッドが実行された「ローカル」コレクションのドキュメント フィールドを参照します。
次の新しい簡潔な構文により、$expr
演算子内の外部フィールドとローカルフィールドを等価一致させる必要がなくなります。
{ $lookup: { from: <foreign collection>, localField: <field from local collection's documents>, foreignField: <field from foreign collection's documents>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run> ], as: <output array field> } }
$lookup
は、次のフィールドを含むドキュメントを受け入れます。
フィールド | 説明 |
---|---|
ローカルコレクションに結合する同じデータベース内の外部コレクションを指定します。
MongoDB 5.1 以降では、 | |
ローカルドキュメントの ローカルドキュメントに | |
外部ドキュメントの 外部ドキュメントに | |
任意。パイプラインステージで使用する変数を指定します。変数式を使用して、 パイプラインステージで変数を参照するには、 let
| |
外部コレクションで実行する には
パイプラインステージで変数を参照するには、 let
| |
外部ドキュメントに追加する新しい配列フィールドの名前を指定します。新しい配列フィールドには、外部コレクションからの一致するドキュメントが含まれます。指定した名前がすでに外部ドキュメントに存在する場合、既存のフィールドは上書きされます。 |
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, <output array field> FROM localCollection WHERE <output array field> IN ( SELECT <documents as determined from the pipeline> FROM <foreignCollection> WHERE <foreignCollection.foreignField> = <localCollection.localField> AND <pipeline match condition> );
以下の例を参照してください。
動作
ビューと照合
$lookup
や $graphLookup
のように複数のビューを含む集計を実行する場合、ビューの照合順序は同じである必要があります。
制限事項
$lookup
ステージには、$out
ステージや $merge
ステージを含めることはできません。具体的には、結合コレクションのパイプラインを指定するときに、pipeline
フィールドにどちらのステージも含めることはできません。
{ $lookup: { from: <collection to join>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to execute on the joined collection> ], // Cannot include $out or $merge as: <output array field> } }
Atlas Search サポート
MongoDB 6.0 以降では、 $lookup
パイプラインで Atlas Search $search
または $searchMeta
ステージを指定して、Atlas クラスター上のコレクションを検索できます。$search
または $searchMeta
ステージは、 $lookup
パイプライン内の最初のステージである必要があります。
たとえば、結合コレクションで条件とサブクエリを結合するか、簡潔な構文を使用して相関サブクエリを実行する 場合は、以下に示すようにパイプライン内で$search
または$searchMeta
を指定できます。
[{ "$lookup": { "from": <joined collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$search": { "<operator>": { <operator-specification> } }, ... }] } }]
[{ "$lookup": { "from": <joined collection>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, "as": <output array field>, "pipeline": [{ "$searchMeta": { "<collector>": { <collector-specification> } }, ... }] } }]
$lookup
とともに $search
を使った例については、Atlas Search チュートリアルの「$lookup を使用した Atlas Search $search クエリの実行」を参照してください。
シャーディングされたコレクション
MongoDB5.1 以降では、from
ステージの パラメーターで$lookup
シャーディングされたコレクション を指定できます。
MongoDB 8.0 以降では、シャーディングされたコレクションをターゲットにしながら、トランザクション内で $lookup
ステージを使用できます。
スロットベースのクエリ実行エンジン
バージョン 6.0 以降、MongoDB は、パイプライン内の先行するすべてのステージもスロット ベースの実行エンジンで実行でき、次の条件のいずれも当てはまらない場合、スロット ベースの実行クエリ エンジンを使用して $lookup
ステージを実行できます。
$lookup
操作は、結合されたコレクション上でパイプラインを実行します。 この種の操作の例については、「結合されたコレクションの結合条件とサブクエリ 」を参照してください。$lookup
のlocalField
またはforeignField
は数値コンポーネントを指定します。例:{ localField: "restaurant.0.review" }
。パイプラインに含まれる任意の
$lookup
のfrom
フィールドには、ビューまたはシャーディングされたコレクションが明示されます。
詳細については、「$lookup
最適化」を参照してください。
パフォーマンスに関する考慮事項
$lookup
パフォーマンスは、実行される操作の種類によって異なります。さまざまな$lookup
操作のパフォーマンスに関する考慮事項については、次の表を参照してください。
$lookup 操作 | パフォーマンスに関する考慮事項 |
---|---|
| |
| |
|
一般的なパフォーマンス戦略については、「インデックス戦略」と「クエリの最適化」を参照してください。
重要
クエリ内で$lookup
を過度に使用すると、パフォーマンスが低下する可能性があります。複数の$lookup
ステージを回避するには、埋め込みデータモデルを使用してクエリ パフォーマンスを最適化することを検討してください。
例
1 つの等価結合の実行 $lookup
これらのドキュメントを使用してコレクションorders
を作成します。
db.orders.insertMany( [ { "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 }, { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 }, { "_id" : 3 } ] )
これらのドキュメントを使用して別のコレクションinventory
を作成します。
db.inventory.insertMany( [ { "_id" : 1, "sku" : "almonds", "description": "product 1", "instock" : 120 }, { "_id" : 2, "sku" : "bread", "description": "product 2", "instock" : 80 }, { "_id" : 3, "sku" : "cashews", "description": "product 3", "instock" : 60 }, { "_id" : 4, "sku" : "pecans", "description": "product 4", "instock" : 70 }, { "_id" : 5, "sku": null, "description": "Incomplete" }, { "_id" : 6 } ] )
orders
コレクションに対する次の集計操作は、orders
コレクションのフィールドitem
と inventory
コレクションのsku
フィールドを使用して、orders
のドキュメントと inventory
コレクションのドキュメントを結合します。
db.orders.aggregate( [ { $lookup: { from: "inventory", localField: "item", foreignField: "sku", as: "inventory_docs" } } ] )
この操作では、次のドキュメントが返されます。
{ "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2, "inventory_docs" : [ { "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 } ] } { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1, "inventory_docs" : [ { "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 } ] } { "_id" : 3, "inventory_docs" : [ { "_id" : 5, "sku" : null, "description" : "Incomplete" }, { "_id" : 6 } ] }
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, inventory_docs FROM orders WHERE inventory_docs IN ( SELECT * FROM inventory WHERE sku = orders.item );
詳細については、「等価一致のパフォーマンスに関する考慮事項」を参照してください。
配列で $lookup
を使用する
localField
が配列の場合、$unwind
ステージを使用せずに、配列要素をスカラーforeignField
と照合できます。
たとえば、次のドキュメントを使用してコレクション例「classes
」を作成します。
db.classes.insertMany( [ { _id: 1, title: "Reading is ...", enrollmentlist: [ "giraffe2", "pandabear", "artie" ], days: ["M", "W", "F"] }, { _id: 2, title: "But Writing ...", enrollmentlist: [ "giraffe1", "artie" ], days: ["T", "F"] } ] )
これらのドキュメントを使用して別のコレクションmembers
を作成します。
db.members.insertMany( [ { _id: 1, name: "artie", joined: new Date("2016-05-01"), status: "A" }, { _id: 2, name: "giraffe", joined: new Date("2017-05-01"), status: "D" }, { _id: 3, name: "giraffe1", joined: new Date("2017-10-01"), status: "A" }, { _id: 4, name: "panda", joined: new Date("2018-10-11"), status: "A" }, { _id: 5, name: "pandabear", joined: new Date("2018-12-01"), status: "A" }, { _id: 6, name: "giraffe2", joined: new Date("2018-12-01"), status: "D" } ] )
次の集計操作では、enrollmentlist
フィールドと name
フィールドを一致させて、classes
コレクション内のドキュメントをmembers
コレクションと結合します。
db.classes.aggregate( [ { $lookup: { from: "members", localField: "enrollmentlist", foreignField: "name", as: "enrollee_info" } } ] )
この操作では、以下を返します。
{ "_id" : 1, "title" : "Reading is ...", "enrollmentlist" : [ "giraffe2", "pandabear", "artie" ], "days" : [ "M", "W", "F" ], "enrollee_info" : [ { "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" }, { "_id" : 5, "name" : "pandabear", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "A" }, { "_id" : 6, "name" : "giraffe2", "joined" : ISODate("2018-12-01T00:00:00Z"), "status" : "D" } ] } { "_id" : 2, "title" : "But Writing ...", "enrollmentlist" : [ "giraffe1", "artie" ], "days" : [ "T", "F" ], "enrollee_info" : [ { "_id" : 1, "name" : "artie", "joined" : ISODate("2016-05-01T00:00:00Z"), "status" : "A" }, { "_id" : 3, "name" : "giraffe1", "joined" : ISODate("2017-10-01T00:00:00Z"), "status" : "A" } ] }
$lookup
を $mergeObjects
で使用する
$mergeObjects
演算子は、複数のドキュメントを 1 つのドキュメントに結合します。
これらのドキュメントを使用してコレクションorders
を作成します。
db.orders.insertMany( [ { "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 }, { "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 } ] )
これらのドキュメントを使用して別のコレクションitems
を作成します。
db.items.insertMany( [ { "_id" : 1, "item" : "almonds", description: "almond clusters", "instock" : 120 }, { "_id" : 2, "item" : "bread", description: "raisin and nut bread", "instock" : 80 }, { "_id" : 3, "item" : "pecans", description: "candied pecans", "instock" : 60 } ] )
次の操作では、まず$lookup
ステージを使用してitem
フィールドで 2 つのコレクションを結合し、次に$replaceRoot
の$mergeObjects
を使用してitems
とorders
の結合されたドキュメントをマージします。
db.orders.aggregate( [ { $lookup: { from: "items", localField: "item", // field in the orders collection foreignField: "item", // field in the items collection as: "fromItems" } }, { $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$fromItems", 0 ] }, "$$ROOT" ] } } }, { $project: { fromItems: 0 } } ] )
この操作では、次のドキュメントが返されます。
{ _id: 1, item: 'almonds', description: 'almond clusters', instock: 120, price: 12, quantity: 2 }, { _id: 2, item: 'pecans', description: 'candied pecans', instock: 60, price: 20, quantity: 1 }
複数の結合条件と相関サブクエリの使用
パイプラインは結合されたコレクションに対して実行でき、複数の結合条件を含めることができます。$expr
演算子を使用すると、接続詞や不等価一致など、より複雑な結合条件が可能になります。
結合条件は、aggregate()
メソッドが実行されたローカル コレクション内のフィールドを参照し、結合されたコレクション内のフィールドを参照できます。これにより、2 つのコレクション間の相関サブクエリが可能になります。
MongoDB 5.0 は簡潔な相関サブクエリをサポートしています。
これらのドキュメントを使用してコレクションorders
を作成します。
db.orders.insertMany( [ { "_id" : 1, "item" : "almonds", "price" : 12, "ordered" : 2 }, { "_id" : 2, "item" : "pecans", "price" : 20, "ordered" : 1 }, { "_id" : 3, "item" : "cookies", "price" : 10, "ordered" : 60 } ] )
これらのドキュメントを使用して別のコレクションwarehouses
を作成します。
db.warehouses.insertMany( [ { "_id" : 1, "stock_item" : "almonds", warehouse: "A", "instock" : 120 }, { "_id" : 2, "stock_item" : "pecans", warehouse: "A", "instock" : 80 }, { "_id" : 3, "stock_item" : "almonds", warehouse: "B", "instock" : 60 }, { "_id" : 4, "stock_item" : "cookies", warehouse: "B", "instock" : 40 }, { "_id" : 5, "stock_item" : "cookies", warehouse: "A", "instock" : 80 } ] )
次の例:
orders.item
フィールドとwarehouse.stock_item
フィールドを結合した相関サブクエリを使用します。在庫品の数量が注文数量を満たせることを確認します。
db.orders.aggregate( [ { $lookup: { from: "warehouses", let: { order_item: "$item", order_qty: "$ordered" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$stock_item", "$$order_item" ] }, { $gte: [ "$instock", "$$order_qty" ] } ] } } }, { $project: { stock_item: 0, _id: 0 } } ], as: "stockdata" } } ] )
この操作では、次のドキュメントが返されます。
{ _id: 1, item: 'almonds', price: 12, ordered: 2, stockdata: [ { warehouse: 'A', instock: 120 }, { warehouse: 'B', instock: 60 } ] }, { _id: 2, item: 'pecans', price: 20, ordered: 1, stockdata: [ { warehouse: 'A', instock: 80 } ] }, { _id: 3, item: 'cookies', price: 10, ordered: 60, stockdata: [ { warehouse: 'A', instock: 80 } ] }
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, stockdata FROM orders WHERE stockdata IN ( SELECT warehouse, instock FROM warehouses WHERE stock_item = orders.item AND instock >= orders.ordered );
$expr
演算子に配置されている $eq
、$lt
、$lte
、$gt
、$gte
比較演算子では、$lookup
ステージで参照される from
コレクションにインデックスを使用できます。制限:
インデックスはフィールドと定数の比較にのみ使用できるため、
let
オペランドは定数に変換する必要があります。たとえば、
$a
と定数値の比較にはインデックスを使用できますが、$a
と$b
の比較には使用できません。let
オペランドが空の値または欠損値に変換される場合の比較には、インデックスは使用されません。
たとえば、インデックス{ stock_item: 1, instock: 1 }
warehouses
コレクションに存在する場合:
warehouses.stock_item
フィールドの等価一致はインデックスを使用します。warehouses.instock
フィールドのクエリの範囲部分でも、複合インデックス内のインデックス付きフィールドが使用されます。
非相関サブクエリの実行 $lookup
集計パイプラインの $lookup
ステージでは、結合コレクションに対してパイプラインを実行できるため、非相関サブクエリが可能になります。非相関サブクエリでは、結合されたドキュメント フィールドは参照されません。
注意
MongoDB5.0 以降では、$lookup
$sample
ステージ、$sampleRate
演算子、または$rand
演算子を含む、 パイプライン ステージ内の相関のないサブクエリの場合、繰り返される場合はサブクエリが常に再度実行されます。以前は、サブクエリの出力サイズに応じて、サブクエリの出力がキャッシュされるか、サブクエリが再度実行されていました。
これらのドキュメントを使用してコレクションabsences
を作成します。
db.absences.insertMany( [ { "_id" : 1, "student" : "Ann Aardvark", sickdays: [ new Date ("2018-05-01"),new Date ("2018-08-23") ] }, { "_id" : 2, "student" : "Zoe Zebra", sickdays: [ new Date ("2018-02-01"),new Date ("2018-05-23") ] }, ] )
これらのドキュメントを使用して別のコレクションholidays
を作成します。
db.holidays.insertMany( [ { "_id" : 1, year: 2018, name: "New Years", date: new Date("2018-01-01") }, { "_id" : 2, year: 2018, name: "Pi Day", date: new Date("2018-03-14") }, { "_id" : 3, year: 2018, name: "Ice Cream Day", date: new Date("2018-07-15") }, { "_id" : 4, year: 2017, name: "New Years", date: new Date("2017-01-01") }, { "_id" : 5, year: 2017, name: "Ice Cream Day", date: new Date("2017-07-16") } ] )
次の操作では、absences
コレクションをholidays
コレクションの 2018 年の休日情報と結合します。
db.absences.aggregate( [ { $lookup: { from: "holidays", pipeline: [ { $match: { year: 2018 } }, { $project: { _id: 0, date: { name: "$name", date: "$date" } } }, { $replaceRoot: { newRoot: "$date" } } ], as: "holidays" } } ] )
この操作では、以下を返します。
{ _id: 1, student: 'Ann Aardvark', sickdays: [ ISODate("2018-05-01T00:00:00.000Z"), ISODate("2018-08-23T00:00:00.000Z") ], holidays: [ { name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") }, { name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") }, { name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z") } ] }, { _id: 2, student: 'Zoe Zebra', sickdays: [ ISODate("2018-02-01T00:00:00.000Z"), ISODate("2018-05-23T00:00:00.000Z") ], holidays: [ { name: 'New Years', date: ISODate("2018-01-01T00:00:00.000Z") }, { name: 'Pi Day', date: ISODate("2018-03-14T00:00:00.000Z") }, { name: 'Ice Cream Day', date: ISODate("2018-07-15T00:00:00.000Z") } ] }
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, holidays FROM absences WHERE holidays IN ( SELECT name, date FROM holidays WHERE year = 2018 );
詳細については、「非相関サブクエリのパフォーマンスに関する検討事項 」を参照してください。
簡潔な相関サブクエリの実行 $lookup
バージョン 5.0 で追加
MongoDB 5.0以降、集計パイプラインの$lookup
ステージでは、コレクション間の結合を改善する簡潔な相関サブクエリ構文がサポートされています。 新しい簡潔な構文により、 ステージの$expr
$match
演算子内の外部フィールドとローカルフィールドを等価一致させる必要がなくなります。
コレクション restaurants
を以下ように作成します。
db.restaurants.insertMany( [ { _id: 1, name: "American Steak House", food: [ "filet", "sirloin" ], beverages: [ "beer", "wine" ] }, { _id: 2, name: "Honest John Pizza", food: [ "cheese pizza", "pepperoni pizza" ], beverages: [ "soda" ] } ] )
食べ物と任意の飲み物の注文を含む別のコレクションorders
を作成します。
db.orders.insertMany( [ { _id: 1, item: "filet", restaurant_name: "American Steak House" }, { _id: 2, item: "cheese pizza", restaurant_name: "Honest John Pizza", drink: "lemonade" }, { _id: 3, item: "cheese pizza", restaurant_name: "Honest John Pizza", drink: "soda" } ] )
次の例:
orders.restaurant_name
の localField とrestaurants.name
の foreignField を一致させることにより、orders
コレクションとrestaurants
コレクションを結合します。一致はpipeline
が実行される前に実行されます。それぞれ
$$orders_drink
と$beverages
を使用してアクセスされるorders.drink
フィールドとrestaurants.beverages
フィールド間で$in
配列の一致を実行します。
db.orders.aggregate( [ { $lookup: { from: "restaurants", localField: "restaurant_name", foreignField: "name", let: { orders_drink: "$drink" }, pipeline: [ { $match: { $expr: { $in: [ "$$orders_drink", "$beverages" ] } } } ], as: "matches" } } ] )
orders.drink
フィールドとrestaurants.beverages
フィールドにsoda
値の一致があります。この出力は matches
配列を表示し、一致する restaurants
コレクションからのすべての結合フィールドを含みます。
{ "_id" : 1, "item" : "filet", "restaurant_name" : "American Steak House", "matches" : [ ] } { "_id" : 2, "item" : "cheese pizza", "restaurant_name" : "Honest John Pizza", "drink" : "lemonade", "matches" : [ ] } { "_id" : 3, "item" : "cheese pizza", "restaurant_name" : "Honest John Pizza", "drink" : "soda", "matches" : [ { "_id" : 2, "name" : "Honest John Pizza", "food" : [ "cheese pizza", "pepperoni pizza" ], "beverages" : [ "soda" ] } ] }
簡潔な相関サブクエリが導入される前は、複数の結合条件および相関サブクエリの使用で示されているように、pipeline
$lookup
の $expr
演算子にある、ローカルフィールドと結合フィールド間の $eq
等価一致を使う必要がありました。
この例では、MongoDB バージョン 5.0 以前の古い冗語構文を使用しており、以前の簡潔な例と同様の結果を返します。
db.orders.aggregate( [ { $lookup: { from: "restaurants", let: { orders_restaurant_name: "$restaurant_name", orders_drink: "$drink" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$$orders_restaurant_name", "$name" ] }, { $in: [ "$$orders_drink", "$beverages" ] } ] } } } ], as: "matches" } } ] )
前の例は、次の疑似 SQL ステートメントに対応します。
SELECT *, matches FROM orders WHERE matches IN ( SELECT * FROM restaurants WHERE restaurants.name = orders.restaurant_name AND restaurants.beverages = orders.drink );
詳細については、「相関サブクエリのパフォーマンスに関する検討事項」を参照してください。
サブパイプラインの名前空間
MongoDB 8.0 以降では、from
フィールドと coll
フィールドが正しく使用されるように、$lookup
と $unionWith
内のサブパイプラインの名前空間が検証されます。
$lookup
の場合、指定されたコレクションを必要としないステージを持つサブパイプラインを使用する場合は、from
フィールドを省略する(例:$documents
ステージ)。同様に、
$unionWith
の場合、coll
フィールドを省略する。
変更されていない動作:
コレクションのステージで開始される
$lookup
の場合(例:$match
サブパイプラインまたは$collStats
サブパイプライン)、from
フィールドを含め、コレクションを指定する必要があります。同様に、
$unionWith
の場合は、coll
フィールドを含め、コレクションを指定します。
次のシナリオは例です。
コレクション cakeFlavors
を以下ように作成します。
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
MongoDB 8.0 以降、次の例では、無効な from
フィールドが含まれているためエラーが返されます。
db.cakeFlavors.aggregate( [ { $lookup: { from: "cakeFlavors", pipeline: [ { $documents: [ {} ] } ], as: "test" } } ] )
8.0 より前の MongoDB バージョンでは、前の例が実行されます。
有効な from
フィールドの例については、「$lookup
を使用して単一の等価一致を実行する」を参照してください。