定義
$lookupバージョン5.1で変更。
Performs a left outer join to a collection in the same database to filter in documents from the foreign collection for processing. The
$lookupstage adds a new array field to each input document. The new array field contains the matching documents from the foreign collection. The$lookupstage passes these reshaped documents to the next stage.Starting in MongoDB 5.1, you can use
$lookupwith sharded collections.2 つの異なるコレクションの要素を結合するには、
$unionWithパイプライン ステージを使用します。重要
$lookupperformance, as with any other query performance, depends on the operation type and whether the foreign field is indexed. Unindexed or correlated-subquery$lookupoperations on large collections can slow down query performance. To reduce reliance on$lookup, consider an embedded data model to store related data in a single collection.For details on
$lookupperformance by operation type, see Performance Considerations.
互換性
次の環境でホストされる配置には $lookup を使用できます。
- MongoDB Atlas はクラウドでの MongoDB 配置のための完全管理サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
The $lookup stage syntax:
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run> ], as: <output array field> } }
The $lookup accepts a document with these fields:
フィールド | 必要性 | 説明 |
|---|---|---|
必須 | ローカルコレクションに結合する同じデータベース内の外部コレクションを指定します。 場合によっては、 MongoDB 5.1 以降では、 | |
| Specifies the field from the documents input to the | |
| 外部ドキュメントの If a foreign document does not contain a | |
任意 | Specifies variables to use in the pipeline stages. Use the variable expressions to access the fields from the local collection's documents that are input to the To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
| 外部コレクションで実行する には The To reference variables in pipeline stages, use the The let variables can be accessed by the stages in the pipeline, including additional
| |
必須 | 入力ドキュメントに追加する新しい配列フィールドの名前を指定します。新しい配列フィールドには、 |
1 つの結合条件による等価一致
To perform an equality match between a field from the input documents with a field from the documents of the foreign collection, the $lookup stage has this syntax:
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, pipeline: [ <pipeline to run> ], as: <output array field> } }
注意
この例では 、pipeline は任意であり、ローカルと外部の等価ステージの後に実行されます。
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, ( SELECT ARRAY_AGG(*) FROM <collection to join> WHERE <foreignField> = <collection.localField> ) AS <output array field> FROM collection;
注意
このページの SQL ステートメントは、MongoDB 集計パイプライン構文の比較に含まれています。SQL ステートメントは実行できません。
MongoDB の例については、次のページを参照してください。
外部コレクションの結合条件とサブクエリ
MongoDB は以下をサポートします。
外部コレクションでパイプラインを実行する。
複数の結合条件。
相関サブクエリと非相関サブクエリ。
In MongoDB, an uncorrelated subquery means that every input document returns the same result. A correlated subquery is a pipeline in a $lookup stage that uses the local or input collection's fields to return results correlated to each incoming document.
注意
Starting in MongoDB 5.0, for an uncorrelated subquery in a $lookup pipeline stage containing a $sample stage, the $sampleRate operator, or the $rand operator, the subquery is always run again if repeated. Previously, depending on the subquery output size, either the subquery output was cached or the subquery was run again.
MongoDB 相関サブクエリは、内部クエリが外部クエリ値を参照する SQL 相関サブクエリに相当します。SQL 非相関サブクエリは、外部クエリ値を参照しません。
MongoDB 5.0 は簡潔な相関サブクエリもサポートしています。
To perform correlated and uncorrelated subqueries with two collections, and perform other join conditions besides a single equality match, use this $lookup syntax:
{ $lookup: { from: <foreign collection>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to run on foreign collection> ], as: <output array field> } }
この操作は、次の疑似 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()メソッドが実行された「ローカル」コレクションのドキュメントフィールドを参照します。
The following new concise syntax removes the requirement for an equality match on the foreign and local fields inside an $expr operator:
{ $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> } }
この操作は、次の疑似 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> );
以下の例を参照してください。
動作
ビューと照合
If performing an aggregation that involves multiple views, such as with $lookup or $graphLookup, the views must have the same collation.
制限事項
You cannot include the $out or the $merge stage in the $lookup stage. That is, when specifying a pipeline for the foreign collection, you cannot include either stage in the pipeline field.
{ $lookup: { from: <collection to join>, let: { <var_1>: <expression>, …, <var_n>: <expression> }, pipeline: [ <pipeline to execute on the foreign collection> ], // Cannot include $out or $merge as: <output array field> } }
Atlas Search サポート
MongoDB6.0 以降では、 パイプラインで Atlas Search$search $searchMetaまたは$lookup ステージを指定して、Atlas クラスター上のコレクションを検索できます。$search $searchMetaまたは ステージは、$lookup パイプライン内の最初のステージである必要があります。
For example, when you Join Conditions and Subqueries on a Foreign Collection or run Correlated Subqueries Using Concise Syntax, you can specify $search or $searchMeta inside the pipeline as shown below:
To see an example of $lookup with $search, see the Atlas Search tutorial Run an Atlas Search $search Query Using $lookup.
シャーディングされたコレクション
Starting in MongoDB 5.1, you can specify sharded collections in the from parameter of $lookup stages.
シャーディングされたコレクションをターゲットにしている間は、トランザクション内で $lookup ステージを使用できません。
スロットベースのクエリ実行エンジン
注意
バージョン 7.0.17 以降、スロットベースのクエリ実行エンジンは、7.0 のパッチ バージョンではデフォルトで有効ではなくなりました。スロットベースのクエリ実行エンジンを使用するクエリを使用する場合は、バージョン 8.0 にアップグレードしてください。デフォルトで有効になっている 。
Starting in version 6.0, MongoDB can use the slot-based execution query engine to execute $lookup stages if all preceding stages in the pipeline can also be executed by the slot-based execution engine and none of the following conditions are true:
$lookup操作は、外部コレクションに対してパイプラインを実行します。この種の操作の例については、「外部コレクションの結合条件とサブクエリ」を参照してください。$lookupのlocalFieldまたはforeignFieldは数値コンポーネントを指定します。例:{ localField: "restaurant.0.review" }。パイプラインに含まれる任意の
$lookupのfromフィールドには、ビューまたはシャーディングされたコレクションが明示されます。
詳細については、「$lookup 最適化」を参照してください。
パフォーマンスに関する考慮事項
$lookup パフォーマンスは、実行される操作の種類によって異なります。さまざまな$lookup操作のパフォーマンスに関する考慮事項については、次の表を参照してください。
$lookup 操作 | パフォーマンスに関する考慮事項 |
|---|---|
| |
| |
|
例
このページの例では、sample_mflixサンプルデータセットのデータを使用します。このデータセットを自己管理型MongoDB配置にロードする方法の詳細については、サンプルデータセットをロードする を参照してください。サンプルデータベースに変更を加えた場合、このページの例を実行するには、データベースを削除して再作成する必要がある場合があります。
1 つの等価結合の実行 $lookup
次の集計操作では、まず moviesコレクションをruntime が 1000 より大きい映画をフィルタリングし、次に _id フィールドと movie_id フィールドの commentsコレクションと結合します。
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "movie_comments" } }, { $project: { _id: 0, title: 1, year: 1, "movie_comments.name": 1, "movie_comments.text": 1, "movie_comments.date": 1 } } ] )
[ { title: 'Centennial', year: 1978, movie_comments: [ { name: 'Ellaria Sand', text: 'Excepturi nam nam eum possimus aspernatur autem. Quis nulla optio praesentium ut distinctio explicabo.', date: ISODate('1995-08-18T03:01:50.000Z') } ] }, { title: 'Baseball', year: 1994, movie_comments: [] } ]
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, movie_comments FROM movies WHERE movie_comments IN ( SELECT * FROM comments WHERE movie_id = movies._id );
詳細については、「等価一致のパフォーマンスに関する考慮事項」をご覧ください。
配列で $lookup を使用する
localFieldが配列の場合、$unwindステージを使用せずに、配列要素をスカラーforeignFieldと照合できます。
次の集計操作では、moviesコレクションと usersコレクションを結合し、movies の cast 配列フィールドと users のスカラー nameフィールドを照合します。
db.movies.aggregate( [ { $match: { title: { $in: [ "Roger & Me", "The Sum of Us", "Centennial" ] } } }, { $lookup: { from: "users", localField: "cast", foreignField: "name", as: "cast_users" } }, { $project: { _id: 0, title: 1, year: 1, cast: 1, "cast_users.name": 1, "cast_users.email": 1 } }, { $sort: { year: 1 } } ] )
[ { cast: [ 'Raymond Burr', 'Barbara Carrera', 'Richard Chamberlain', 'Robert Conrad' ], title: 'Centennial', year: 1978, cast_users: [] }, { cast: [ 'Michael Moore', 'Roger B. Smith', 'Rhonda Britton', 'Fred Ross' ], title: 'Roger & Me', year: 1989, cast_users: [ { name: 'Michael Moore', email: 'michael_moore@fakegmail.com' } ] }, { cast: [ 'Jack Thompson', 'Russell Crowe', 'John Polson', 'Deborah Kennedy' ], title: 'The Sum of Us', year: 1994, cast_users: [ { name: 'Deborah Kennedy', email: 'deborah_kennedy@fakegmail.com' } ] } ]
$lookup を $mergeObjects で使用する
$mergeObjects 演算子は、複数のドキュメントを 1 つのドキュメントに結合します。
The following operation uses $lookup to join the movies collection with the comments collection, then uses $mergeObjects in $replaceRoot to merge the first comment document with the movie document:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "movie_comments" } }, { $replaceRoot: { newRoot: { $mergeObjects: [ { $arrayElemAt: [ "$movie_comments", 0 ] }, "$$ROOT" ] } } }, { $project: { _id: 0, title: 1, year: 1, genres: 1, name: 1, email: 1, text: 1, date: 1 } } ] )
[ { name: 'Ellaria Sand', email: 'indira_varma@gameofthron.es', text: 'Excepturi nam nam eum possimus aspernatur autem. Quis nulla optio praesentium ut distinctio explicabo.', date: ISODate('1995-08-18T03:01:50.000Z'), genres: [ 'Action', 'Adventure', 'Drama' ], title: 'Centennial', year: 1978 }, { genres: [ 'Documentary', 'History', 'Sport' ], title: 'Baseball', year: 1994 } ]
複数の結合条件と相関サブクエリの使用
パイプラインは外部コレクションに対して実行でき、複数の結合条件を含めることができます。$expr 演算子を使用すると、接続詞や不等価一致など、より複雑な結合条件が可能になります。
結合条件は、aggregate()メソッドが実行されたローカル コレクション内のフィールドを参照し、外部コレクション内のフィールドを参照できます。これにより、2つのコレクション間の相関サブクエリが可能になります。
MongoDB 5.0 は簡潔な相関サブクエリをサポートしています。
次の例:
_idフィールドとmovie_idフィールドを使用してmoviesコレクションとcommentsコレクションを結合します。映画の公開年後に投稿されたコメントのみを含めるようにコメントをフィルタリングします。
db.movies.aggregate( [ { $match: { title: { $in: [ "Class Action", "Kafka", "Corpse Bride" ] } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", let: { movie_year: "$year" }, pipeline: [ { $match: { $expr: { $gt: [ { $year: "$date" }, "$$movie_year" ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { year: 1991, title: 'Class Action', post_release_comments: [ { name: 'Khal Drogo', date: ISODate('2016-12-06T07:17:03.000Z') } ] }, { year: 1991, title: 'Kafka', post_release_comments: [ { name: 'Khal Drogo', date: ISODate('1998-05-10T03:10:20.000Z') } ] }, { year: 2005, title: 'Corpse Bride', post_release_comments: [] } ]
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, post_release_comments FROM movies WHERE post_release_comments IN ( SELECT name, date FROM comments WHERE movie_id = movies._id AND YEAR(date) > movies.year );
The $eq, $lt, $lte, $gt, and $gte comparison operators placed in an $expr operator can use an index on the from collection referenced in a $lookup stage. Limitations:
インデックスはフィールドと定数の比較にのみ使用できるため、
letオペランドは定数に変換する必要があります。たとえば、
$aと定数値の比較にはインデックスを使用できますが、$aと$bの比較には使用できません。letオペランドが空の値または欠損値に変換される場合の比較には、インデックスは使用されません。
たとえば、インデックス{ movie_id: 1 } commentsコレクションに存在する場合:
comments.movie_idフィールドの等価一致はインデックスを使用します。
非相関サブクエリの実行 $lookup
An aggregation pipeline $lookup stage can execute a pipeline on the foreign collection, which allows uncorrelated subqueries. An uncorrelated subquery does not reference the local document fields.
注意
Starting in MongoDB 5.0, for an uncorrelated subquery in a $lookup pipeline stage containing a $sample stage, the $sampleRate operator, or the $rand operator, the subquery is always run again if repeated. Previously, depending on the subquery output size, either the subquery output was cached or the subquery was run again.
次の操作では、moviesコレクションからの さらに 上映時間が 1000 分を超える映画と usersコレクションを結合します。
db.users.aggregate( [ { $match: { email: { $in: [ "mark_addy@gameofthron.es", "lena_headey@gameofthron.es" ] } } }, { $lookup: { from: "movies", pipeline: [ { $match: { runtime: { $gt: 1000 } } }, { $project: { _id: 0, title: 1, year: 1 } } ], as: "long_movies" } }, { $project: { _id: 0, name: 1, email: 1, long_movies: 1 } } ] )
[ { name: 'Robert Baratheon', email: 'mark_addy@gameofthron.es', long_movies: [ { title: 'Centennial', year: 1978 }, { title: 'Baseball', year: 1994 } ] }, { name: 'Cersei Lannister', email: 'lena_headey@gameofthron.es', long_movies: [ { title: 'Centennial', year: 1978 }, { title: 'Baseball', year: 1994 } ] } ]
この操作は、次の疑似 SQL ステートメントに対応します。
SELECT *, long_movies FROM users WHERE long_movies IN ( SELECT title, year FROM movies WHERE runtime > 1000 );
詳細については、「非相関サブクエリのパフォーマンスに関する検討事項」を参照してください。
簡潔な相関サブクエリの実行 $lookup
バージョン 5.0 の新機能。
Starting in MongoDB 5.0, an aggregation pipeline $lookup stage supports a concise correlated subquery syntax that improves joins between collections. The new concise syntax removes the requirement for an equality match on the foreign and local fields inside of an $expr operator in a $match stage.
次の例:
Joins the
moviesandcommentscollections by matching the localField_idwith the foreignFieldmovie_id. The match is performed before thepipelineis run.それぞれ
$$movie_yearと$dateを使用してアクセスされた、映画の公開年後に投稿されたもののみを含むようにコメントをフィルタリングします。
db.movies.aggregate( [ { $match: { title: { $in: [ "I Don't Kiss", "Lucky Luke", "Mississippi Masala" ] } } }, { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", let: { movie_year: "$year" }, pipeline: [ { $match: { $expr: { $gt: [ { $year: "$date" }, "$$movie_year" ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { title: "I Don't Kiss", year: 1991, post_release_comments: [ { name: 'Brandon Hardy', date: ISODate('2016-09-18T11:11:34.000Z') } ] }, { title: 'Lucky Luke', year: 1991, post_release_comments: [ { name: 'Kelsey Smith', date: ISODate('2010-01-13T17:55:01.000Z') } ] }, { title: 'Mississippi Masala', year: 1991, post_release_comments: [ { name: 'Phillip Collins', date: ISODate('2010-05-13T08:04:22.000Z') } ] } ]
この例では、MongoDB バージョン 5.0 以前の古い冗語構文を使用しており、以前の簡潔な例と同様の結果を返します。
db.movies.aggregate( [ { $match: { title: { $in: [ "I Don't Kiss", "Lucky Luke", "Mississippi Masala" ] } } }, { $lookup: { from: "comments", let: { movie_id: "$_id", movie_year: "$year" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$movie_id", "$$movie_id" ] }, { $gt: [ { $year: "$date" }, "$$movie_year" ] } ] } } }, { $project: { _id: 0, name: 1, date: 1 } } ], as: "post_release_comments" } }, { $project: { _id: 0, title: 1, year: 1, post_release_comments: 1 } } ] )
[ { title: "I Don't Kiss", year: 1991, post_release_comments: [ { name: 'Brandon Hardy', date: ISODate('2016-09-18T11:11:34.000Z') } ] }, { title: 'Lucky Luke', year: 1991, post_release_comments: [ { name: 'Kelsey Smith', date: ISODate('2010-01-13T17:55:01.000Z') } ] }, { title: 'Mississippi Masala', year: 1991, post_release_comments: [ { name: 'Phillip Collins', date: ISODate('2010-05-13T08:04:22.000Z') } ] } ]
前の例は、次の疑似 SQL ステートメントに対応します。
SELECT *, post_release_comments FROM movies WHERE post_release_comments IN ( SELECT * FROM comments WHERE comments.movie_id = movies._id AND YEAR(comments.date) > movies.year );
詳細については、「相関サブクエリのパフォーマンスに関する考慮事項」をご覧ください。
このページのC#の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。MongoDB Atlasクラスターを無料で作成して、サンプルデータセットをロードする方法については、 MongoDB .NET/ C#ドライバーのドキュメントの「 開始 」を参照してください。
次の Movie クラスは、sample_mflix.movies コレクション内のドキュメントをモデル化します。
[] public class Movie { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; [] public int? Year { get; set; } [] public int? Runtime { get; set; } [] public string? Rated { get; set; } [] public int Metacritic { get; set; } [] public string? Plot { get; set; } [] public string? Type { get; set; } [] public string[]? Cast { get; set; } [] public string[]? Directors { get; set; } [] public string[]? Writers { get; set; } [] public ImdbData? Imdb { get; set; } }
次の Comment クラスは、sample_mflix.comments コレクション内のドキュメントをモデル化します。
[] public class Comment { [] public ObjectId Id { get; set; } [] public ObjectId MovieId { get; set; } [] public string Text { get; set; } = null!; }
次の LookupResult クラスには、$lookup ステージの出力が保存されます。
[] public class LookupResult { [] public ObjectId Id { get; set; } [] public string Title { get; set; } = null!; public List<Comment> Comments { get; set; } = []; }
To use the MongoDB .NET/C# driver to add a $lookup stage to an aggregation pipeline, call the UnionWith() method on a PipelineDefinition object.
次の例では、movies コレクションと comments コレクション間で左外部結合を実行するパイプラインステージを作成します。このコードは、各 Movieドキュメントの IdフィールドをComment ドキュメントの MovieIdフィールドに結合します。各映画のコメントは、各 LookupResultドキュメントの Comments という名前のフィールドに保存されます。
var commentCollection = _client .GetDatabase("sample_mflix") .GetCollection<Comment>("comments"); var pipeline = new EmptyPipelineDefinition<Movie>() .Lookup<Movie, Movie, Comment, LookupResult>( foreignCollection: commentCollection, localField: m => m.Id, foreignField: c => c.MovieId, @as: r => r.Comments);
このページのNode.js の例では、Atlasサンプルデータセット の sample_mflixデータベースを使用します。無料のMongoDB Atlas cluster を作成し、サンプルデータセットをロードする方法については、 MongoDB Node.jsドライバーのドキュメントの開始を参照してください。
MongoDB Node.jsドライバーを使用して $lookup ステージを集計パイプラインに追加するには、パイプラインオブジェクトで $lookup 演算子を使用します。
次の例では、movies コレクションと comments コレクションの間で左外部結合を実行するパイプラインステージを作成します。このコードは、各 movie ドキュメントの _id フィールドを comment ドキュメントの movie_id フィールドに結合します。comments フィールドは、各 movie ドキュメントの各映画に対するコメントを保存します。次に、この例は集計パイプラインを実行します。
const pipeline = [ { $lookup: { from: "comments", localField: "_id", foreignField: "movie_id", as: "comments" } } ]; const cursor = collection.aggregate(pipeline); return cursor;