定義
$lookupバージョン8.0で変更。
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パイプライン ステージを使用します。重要
$lookupを過度に使用すると、クエリ パフォーマンスが低下する可能性があります。$lookupへの依存関係を軽減するには、埋め込みデータモデルを使用して関連データを単一のコレクションに保存することを検討してください。$lookupパフォーマンスの詳細については、パフォーマンスに関する考慮事項 を参照してください。
互換性
次の環境でホストされる配置には $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 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 will return 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()メソッドが実行された「ローカル」コレクションのドキュメントフィールドを参照します。
次の新しい簡潔な構文により、$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> } }
この操作は、次の疑似 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> );
以下の例を参照してください。
動作
暗号化されたコレクション
Starting in MongoDB 8.1, you can reference multiple encrypted collections in a $lookup stage. However, $lookup does not support:
localFieldまたはforeignFieldの結合フィールドとして暗号化されたフィールドを使用する。注意
クライアント側のフィールドレベル暗号化 を使用するドライバーの場合、 自己結合操作を実行している場合にのみ、暗号化されたフィールドを結合フィールドとして使用できます。
ビューと照合
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> } }
MongoDB Search のサポート
Starting in MongoDB 6.0, you can specify the MongoDB Search $search or $searchMeta stage in the $lookup pipeline to search collections on the Atlas cluster. The $search or the $searchMeta stage must be the first stage inside the $lookup pipeline.
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 MongoDB Search tutorial Run a MongoDB Search $search Query Using $lookup.
シャーディングされたコレクション
Starting in MongoDB 5.1, you can specify sharded collections in the from parameter of $lookup stages.
MongoDB 8.0 以降では、シャーディングされたコレクションをターゲットにしながら、トランザクション内で $lookup ステージを使用できます。
スロットベースのクエリ実行エンジン
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 );
詳細については、「相関サブクエリのパフォーマンスに関する考慮事項」をご覧ください。
サブパイプラインの名前空間
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" } ] )
このページの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; } = []; }
MongoDB .NET/ C#ドライバーを使用して$lookup ステージを集計パイプラインに追加するには、 PipelineDefinitionオブジェクトで UnionWith() メソッドを呼び出します。
次の例では、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);
{ "_id" : ObjectId("..."), "title" : "A Corner in Wheat", "Comments" : [ { "_id" : ObjectId("..."), "movie_id" : ObjectId("..."), "text" : "..." }, "..." ] }
このページの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;