Definition定义
$lookupChanged in version 8.0.在版本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.$lookup阶段为每个输入文档添加一个新的数组字段。新的数组字段包含来自外部集合的匹配文档。The$lookupstage passes these reshaped documents to the next stage.$lookup阶段将这些重塑的文档传递到下一阶段。Starting in MongoDB 5.1, you can use从MongoDB 5.1开始,您可以在分片集合中使用$lookupwith sharded collections.$lookup。To combine elements from two different collections, use the要组合来自两个不同集合的元素,请使用$unionWithpipeline stage.$unionWith管道阶段。
Compatibility兼容性
You can use 您可以将$lookup for deployments hosted in the following environments:$lookup用于在以下环境中托管的部署:
- MongoDB Atlas
: The fully managed service for MongoDB deployments in the cloud:云中MongoDB部署的完全托管服务
- MongoDB Enterprise
: The subscription-based, self-managed version of MongoDB:MongoDB的基于订阅的自我管理版本 - MongoDB Community
: The source-available, free-to-use, and self-managed version of MongoDB:MongoDB的源代码可用、免费使用和自我管理版本
Syntax语法
The $lookup stage syntax:$lookup阶段语法:
{
$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:$lookup接受具有以下字段的文档:
from |
| |
localField | pipeline is specifiedpipeline |
|
foreignField | pipeline is specifiedpipeline |
|
let |
| |
pipeline | localField and foreignField are specifiedlocalField和foreignField |
|
as |
|
Equality Match with a Single Join Condition具有单一连接条件的相等匹配
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阶段有以下语法:
{
$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>
}
}
Note
In this example, 在这个例子中,pipeline is optional and runs after the local and foreign equality stage.pipeline是可选的,在本地和外部相等阶段之后运行。
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪SQL语句:
SELECT *, (
SELECT ARRAY_AGG(*)
FROM <collection to join>
WHERE <foreignField> = <collection.localField>
) AS <output array field>
FROM collection;
Note
The SQL statements on this page are included for comparison to the MongoDB aggregation pipeline syntax. The SQL statements aren't runnable.此页面上的SQL语句用于与MongoDB聚合管道语法进行比较。SQL语句无法运行。
For MongoDB examples, see these pages:有关MongoDB示例,请参阅以下页面:
Join Conditions and Subqueries on a Foreign Collection外国托收的加入条件和子查询
MongoDB supports:支持:
Executing a pipeline on a foreign collection.在外部集合上执行管道。Multiple join conditions.多种加入条件。Correlated and uncorrelated subqueries.相关和不相关的子查询。
In MongoDB, an uncorrelated subquery means that every input document will return the same result. A correlated subquery is a pipeline in a 在MongoDB中,不相关的子查询意味着每个输入文档将返回相同的结果。相关子查询是$lookup stage that uses the local or input collection's fields to return results correlated to each incoming document.$lookup阶段的一个管道,它使用本地或input集合的字段返回与每个传入文档相关的结果。
Note
Starting in MongoDB 5.0, for an uncorrelated subquery in a 从MongoDB 5.0开始,对于包含$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.$sample阶段、$sampleRate运算符或$rand运算符的$lookup管道阶段中的不相关子查询,如果重复,子查询总是会再次运行。以前,根据子查询输出的大小,要么缓存子查询输出,要么再次运行子查询。
MongoDB correlated subqueries are comparable to SQL correlated subqueries, where the inner query references outer query values. An SQL uncorrelated subquery does not reference outer query values.MongoDB相关子查询与SQL相关子查询类似,其中内部查询引用外部查询值。SQL不相关的子查询不引用外部查询值。
MongoDB 5.0 also supports concise correlated subqueries.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语法:
{
$lookup:
{
from: <foreign collection>,
let: { <var_1>: <expression>, …, <var_n>: <expression> },
pipeline: [ <pipeline to run on foreign collection> ],
as: <output array field>
}
}
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪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>
);
See the following examples:请参阅以下示例:
Correlated Subqueries Using Concise Syntax使用简洁语法的相关子查询
New in version 5.0.在版本5.0中新增。
Starting in MongoDB 5.0, you can use a concise syntax for a correlated subquery. Correlated subqueries reference document fields from a foreign collection and the "local" collection on which the 从MongoDB 5.0开始,您可以对相关子查询使用简洁的语法。相关子查询引用来自外部集合和运行aggregate() method was run.aggregate()方法的"local"集合的文档字段。
The following new concise syntax removes the requirement for an equality match on the foreign and local fields inside of an 以下新的简洁语法消除了对$expr operator:$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>
}
}
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪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>
);
See this example:请看这个例子:
Behavior行为
Encrypted Collections加密集合
Starting in MongoDB 8.1, you can reference multiple encrypted collections in a 从MongoDB 8.1开始,您可以在$lookup stage. However, $lookup does not support:$lookup阶段引用多个加密集合。但是,$lookup不支持:
Using an encrypted field as the join field in the使用加密字段作为localFieldorforeignField.localField或foreignField中的联接字段。Note
For drivers using Client-Side Field Level Encryption, you can use an encrypted field as a join field only if you are performing a self-join operation.对于使用客户端字段级加密的驱动程序,只有在执行自连接操作时,才能将加密字段用作连接字段。Using any field in an encrypted array. An array is considered as encrypted if it contains any encrypted elements.使用加密数组中的任何字段。如果一个数组包含任何加密元素,则认为它是加密的。
Views and Collation视图和排序
If performing an aggregation that involves multiple views, such as with 如果执行涉及多个视图的聚合,例如使用$lookup or $graphLookup, the views must have the same collation.$lookup或$graphLookup,则这些视图必须具有相同的排序规则。
Restrictions限制
You cannot include the 您不能在$out or the $merge stage in the $lookup stage. $lookup阶段中包含$out或$merge阶段。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 SupportMongoDB搜索支持
Starting in MongoDB 6.0, you can specify the MongoDB Search 从MongoDB 6.0开始,您可以在$search or $searchMeta stage in the $lookup pipeline to search collections on the Atlas cluster. $lookup管道中指定MongoDB Search$Search或$searchMeta阶段,以搜索Atlas集群上的集合。The $search or the $searchMeta stage must be the first stage inside the $lookup pipeline.$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:$search或$searchMeta,如下所示:
$search
[{
"$lookup": {
"from": <foreign 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>
}
},
...
}]
}
}]$searchMeta
[{
"$lookup": {
"from": <foreign 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>
}
},
...
}]
}
}]To see an example of 要查看使用$lookup with $search, see the MongoDB Search tutorial Run a MongoDB Search $search Query Using $lookup.$search的$lookup示例,请参阅MongoDB搜索教程使用$lookup运行MongoDB搜索$search查询。
Sharded Collections分片化集合
Starting in MongoDB 5.1, you can specify sharded collections in the 从MongoDB 5.1开始,您可以在from parameter of $lookup stages.$lookup阶段的from参数中指定分片集合。
Starting in MongoDB 8.0, you can use the 从MongoDB 8.0开始,您可以在事务中使用$lookup stage within a transaction while targeting a sharded collection.$lookup阶段,同时针对分片集合。
Slot-Based Query Execution Engine基于插槽的查询执行引擎
Starting in version 6.0, MongoDB can use the slot-based execution query engine to execute 从6.0版本开始,如果管道中的所有前面阶段也可以由基于槽的执行引擎执行,并且以下条件均不成立,MongoDB可以使用基于槽的运行查询引擎来执行$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阶段:
The$lookupoperation executes a pipeline on a foreign collection. To see an example of this kind of operation, see Join Conditions and Subqueries on a Foreign Collection.$lookup操作在外部集合上执行管道。要查看此类操作的示例,请参阅外部集合上的联接条件和子查询。The$lookup'slocalFieldorforeignFieldspecify numeric components. For example:{ localField: "restaurant.0.review" }.$lookup的localField或foreignField指定了数字组件。例如:{ localField: "restaurant.0.review" }。The任何fromfield of any$lookupin the pipeline specifies a view or sharded collection.$lookup管道中的from字段都指定了一个视图或分片集合。
For more information, see 有关更多信息,请参阅$lookup Optimization.$lookup优化。
Performance Considerations性能考量
$lookup performance depends on the type of operation performed. Refer to the following table for performance considerations for different $lookup operations.$lookup性能取决于执行的操作类型。有关不同$lookup操作的性能考虑,请参阅下表。
$lookup | |
|---|---|
| |
| |
|
For general performance strategies, see Indexing Strategies and Query Optimization.有关一般性能策略,请参阅索引策略和查询优化。
Important
Excessive use of 在查询中过度使用$lookup within a query may slow down performance. $lookup可能会降低性能。To avoid multiple 为了避免多个$lookup stages, consider an embedded data model to optimize query performance.$lookup阶段,可以考虑使用嵌入式数据模型来优化查询性能。
Examples示例
MongoDB Shell
Perform a Single Equality Join with $lookup使用$lookup执行单个相等连接
$lookupCreate a collection 使用以下文档创建集合orders with these documents:orders:
db.orders.insertMany( [
{ _id: 1, item: "almonds", price: 12, quantity: 2 },
{ _id: 2, item: "pecans", price: 20, quantity: 1 },
{ _id: 3 }
] )
Create another collection 使用以下文档创建另一个集合inventory with these documents: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 }
] )
The following aggregation operation on the orders collection joins the documents from orders with the documents from the inventory collection using the fields item from the orders collection and the sku field from the inventory collection:orders集合的以下聚合操作使用orders集合的字段项和inventory集合的sku字段将订单中的文档与inventory集合中的文档连接起来:
db.orders.aggregate( [
{
$lookup:
{
from: "inventory",
localField: "item",
foreignField: "sku",
as: "inventory_docs"
}
}
] )
The operation returns these documents:该操作返回以下文档:
{
_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 }
]
}
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪SQL语句:
SELECT *, inventory_docs
FROM orders
WHERE inventory_docs IN (
SELECT *
FROM inventory
WHERE sku = orders.item
);
For more information, see Equality Match Performance Considerations.有关详细信息,请参阅平等匹配性能考虑因素。
Use $lookup with an Array将$lookup与数组一起使用
$lookup with an ArrayIf the 如果localField is an array, you can match the array elements against a scalar foreignField without an $unwind stage.localField是一个数组,则可以将数组元素与标量foreignField进行匹配,而无需$unwind阶段。
For example, create an example collection 例如,使用以下文档创建一个示例集合classes with these documents: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"] }
] )
Create another collection 使用以下文档创建另一个集合members with these documents:members:
db.members.insertMany( [
{ _id: 1, name: "artie", foreign: new Date("2016-05-01"), status: "A" },
{ _id: 2, name: "giraffe", foreign: new Date("2017-05-01"), status: "D" },
{ _id: 3, name: "giraffe1", foreign: new Date("2017-10-01"), status: "A" },
{ _id: 4, name: "panda", foreign: new Date("2018-10-11"), status: "A" },
{ _id: 5, name: "pandabear", foreign: new Date("2018-12-01"), status: "A" },
{ _id: 6, name: "giraffe2", foreign: new Date("2018-12-01"), status: "D" }
] )
The following aggregation operation joins documents in the 以下聚合操作将classes collection with the members collection, matching on the enrollmentlist field to the name field:classes集合中的文档与members集合连接起来,在enrollmentlist(注册列表)字段上与名称字段匹配:
db.classes.aggregate( [
{
$lookup:
{
from: "members",
localField: "enrollmentlist",
foreignField: "name",
as: "enrollee_info"
}
}
] )
The operation returns the following:该操作返回以下内容:
{
_id: 1,
title: "Reading is ...",
enrollmentlist: [ "giraffe2", "pandabear", "artie" ],
days: [ "M", "W", "F" ],
enrollee_info: [
{ _id: 1, name: "artie", foreign: ISODate("2016-05-01T00:00:00Z"), status: "A" },
{ _id: 5, name: "pandabear", foreign: ISODate("2018-12-01T00:00:00Z"), status: "A" },
{ _id: 6, name: "giraffe2", foreign: 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", foreign: ISODate("2016-05-01T00:00:00Z"), status: "A" },
{ _id: 3, name: "giraffe1", foreign: ISODate("2017-10-01T00:00:00Z"), status: "A" }
]
}Use $lookup with $mergeObjects将$lookup与$mergeObjects一起使用
$lookup with $mergeObjectsThe $mergeObjects operator combines multiple documents into a single document.$mergeObjects运算符将多个文档合并为一个文档。
Create a collection 使用以下文档创建集合orders with these documents:orders:
db.orders.insertMany( [
{ _id: 1, item: "almonds", price: 12, quantity: 2 },
{ _id: 2, item: "pecans", price: 20, quantity: 1 }
] )
Create another collection 使用这些文档创建另一个集合items with these documents: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 }
] )
The following operation first uses the 以下操作首先使用$lookup stage to join the two collections by the item fields and then uses $mergeObjects in the $replaceRoot to merge the foreign documents from items and orders:$lookup阶段按item字段连接两个集合,然后使用$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 } }
] )
The operation returns these documents:该操作返回以下文档:
{
_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
}Use Multiple Join Conditions and a Correlated Subquery使用多个连接条件和相关子查询
Pipelines can execute on a foreign collection and include multiple join conditions. 管道可以在外部集合上执行,并包含多个连接条件。The $expr operator enables more complex join conditions including conjunctions and non-equality matches.$expr运算符支持更复杂的连接条件,包括连词和非等式匹配。
A join condition can reference a field in the local collection on which the 连接条件可以引用本地集合中运行aggregate() method was run and reference a field in the foreign collection. This allows a correlated subquery between the two collections.aggregate()方法的字段,也可以引用外部集合中的字段。这允许在两个集合之间进行相关子查询。
MongoDB 5.0 supports concise correlated subqueries.MongoDB 5.0支持简洁的相关子查询。
Create a collection 使用以下文档创建集合orders with these documents: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 }
] )
Create another collection 使用以下文档创建另一个集合warehouses with these documents: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 }
] )
The following example:以下示例:
Uses a correlated subquery with a join on the在orders.itemandwarehouse.stock_itemfields.orders.item和warehouse.stock_item字段上使用具有联接的相关子查询。Ensures the quantity of the item in stock can fulfill the ordered quantity.确保inventory商品的数量能够满足订购数量。
db.orders.aggregate( [
{
$lookup:
{
from : "warehouses",
localField : "item",
foreignField : "stock_item",
let : { order_qty: "$ordered" },
pipeline : [
{ $match :
{ $expr :
{ $gte: [ "$instock", "$$order_qty" ] }
}
},
{ $project : { stock_item: 0, _id: 0 } }
],
as : "stockdata"
}
}
] )
The operation returns these documents:该操作返回以下文档:
{
_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 } ]
}
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪SQL语句:
SELECT *, stockdata
FROM orders
WHERE stockdata IN (
SELECT warehouse, instock
FROM warehouses
WHERE stock_item = orders.item
AND instock >= orders.ordered
);
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:$expr运算符中的$eq、$lt、$lte、$gt和$gte比较运算符可以在$lookup阶段引用的from集合上使用索引。限制:
Indexes can only be used for comparisons between fields and constants, so the索引只能用于字段和常量之间的比较,因此letoperand must resolve to a constant.let操作数必须解析为常量。For example, a comparison between例如,$aand a constant value can use an index, but a comparison between$aand$bcannot.$a和常量值之间的比较可以使用索引,但$a和$b之间的比较不能。Indexes are not used for comparisons where the当let操作数解析为空值或缺失值时,索引不用于比较。letoperand resolves to an empty or missing value.Multikey indexes are not used.不使用多键索引。
For example, if the index 例如,如果{ stock_item: 1, instock: 1 } exists on the warehouses collection:warehouses(仓库)集合上存在索引{ stock_item: 1, instock: 1 }:
The equality match on thewarehouses.stock_itemfield uses the index.warehouses.stock_item字段上的相等匹配使用索引。The range part of the query on thewarehouses.instockfield also uses the indexed field in the compound index.warehouses.instock字段查询的范围部分也使用复合索引中的索引字段。
Perform an Uncorrelated Subquery with $lookup使用$lookup执行不相关的子查询
$lookupAn 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.$lookup阶段可以在外部集合上执行管道,这允许不相关的子查询。不相关的子查询不引用本地文档字段。
Note
Starting in MongoDB 5.0, for an uncorrelated subquery in a 从MongoDB 5.0开始,对于包含$lookup pipeline stage containing a $sample stage, the $sampleRate operator, or the $rand operator, the subquery is always run again if repeated. $sample阶段、$sampleRate运算符或$rand运算符的$lookup管道阶段中的不相关子查询,如果重复,子查询总是会再次运行。Previously, depending on the subquery output size, either the subquery output was cached or the subquery was run again.以前,根据子查询输出的大小,要么缓存子查询输出,要么再次运行子查询。
Create a collection 使用以下文档创建集合absences with these documents: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") ] },
] )
Create another collection 使用这些文档创建另一个集合holidays with these documents: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") }
] )
The following operation joins the 以下操作将absences collection with 2018 holiday information from the holidays collection: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"
}
}
] )
The operation returns the following:该操作返回以下内容:
{
_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")
}
]
}
The operation corresponds to this pseudo-SQL statement:该操作对应于此伪SQL语句:
SELECT *, holidays
FROM absences
WHERE holidays IN (
SELECT name, date
FROM holidays
WHERE year = 2018
);
For more information, see Uncorrelated Subquery Performance Considerations.有关更多信息,请参阅不相关的子查询性能考虑因素。
Perform a Concise Correlated Subquery with $lookup使用$lookup执行简洁的相关子查询
$lookupNew in version 5.0.在版本5.0中新增。
Starting in MongoDB 5.0, an aggregation pipeline 从MongoDB 5.0开始,聚合管道$lookup stage supports a concise correlated subquery syntax that improves joins between collections. $lookup阶段支持简洁的相关子查询语法,以改进集合之间的连接。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.$match阶段对$expr运算符内的外部和本地字段进行相等匹配的要求。
Create a collection 创建集合restaurants: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" ]
}
] )
Create another collection 创建另一个包含食物和可选饮料订单的集合orders with food and optional drink orders: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"
}
] )
The following example:以下示例:
Joins the通过将ordersandrestaurantscollections by matching theorders.restaurant_namelocalField with therestaurants.nameforeignField. The match is performed before thepipelineis run.orders.restaurant_namelocalField与restaurants.nameforeignField匹配来合并orders和restaurants集合。匹配在管道运行之前执行。Performs an在$inarray match between theorders.drinkandrestaurants.beveragesfields that are accessed using$$orders_drinkand$beveragesrespectively.orders.drink和restaurants.beverages字段之间执行$in数组匹配,这些字段分别使用$$orders_drink和$beverages(饮料)访问。
db.orders.aggregate( [
{
$lookup: {
from: "restaurants",
localField: "restaurant_name",
foreignField: "name",
let: { orders_drink: "$drink" },
pipeline: [ {
$match: {
$expr: { $in: [ "$$orders_drink", "$beverages" ] }
}
} ],
as: "matches"
}
}
] )
There is a match for the 在soda value in the orders.drink and restaurants.beverages fields. This output shows the matches array and contains all foreign fields from the restaurants collection for the match: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" ]
} ]
}
This example uses the older verbose syntax from MongoDB versions before 5.0 and returns the same results as the previous concise example:此示例使用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"
}
}
] )
The previous examples correspond to this pseudo-SQL statement:前面的例子对应于这个伪SQL语句:
SELECT *, matches
FROM orders
WHERE matches IN (
SELECT *
FROM restaurants
WHERE restaurants.name = orders.restaurant_name
AND restaurants.beverages = orders.drink
);
For more information, see Correlated Subquery Performance Considerations.有关更多信息,请参阅相关子查询性能考虑因素。
Namespaces in Subpipelines子管道中的命名空间
Starting in MongoDB 8.0, namespaces in subpipelines within 从MongoDB 8.0开始,$lookup and $unionWith are validated to ensure the correct use of from and coll fields:$lookup和$unionWith子管道中的命名空间经过验证,以确保from和coll字段的正确使用:
For对于$lookup, omit thefromfield if you use a subpipeline with a stage which doesn't require a specified collection. For example, a$documentsstage.$lookup,如果您使用的子管道具有不需要指定集合的阶段,请省略from字段。例如,$documents阶段。Similarly, for同样,对于$unionWith, omit thecollfield.$unionWith,省略coll字段。
Unchanged behavior:行为不变:
For a对于以集合的阶段开始的$lookupthat starts with a stage for a collection, for example a$matchor$collStatssubpipeline, you must include thefromfield and specify the collection.$lookup,例如$match或$collStats子管道,您必须包含from字段并指定集合。Similarly, for同样,对于$unionWith, include thecollfield and specify the collection.$unionWith,包含coll字段并指定集合。
The following scenario shows an example.以下场景显示了一个示例。
Create a collection 创建一个集合cakeFlavors:cakeFlavors(蛋糕口味):
db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )
Starting in MongoDB 8.0, the following example returns an error because it contains an invalid 从MongoDB 8.0开始,以下示例返回错误,因为它包含无效的from field:from字段:
db.cakeFlavors.aggregate( [ {
$lookup: {
from: "cakeFlavors",
pipeline: [ { $documents: [ {} ] } ],
as: "test"
}
} ] )
In MongoDB versions before 8.0, the previous example runs.在MongoDB 8.0之前的版本中,前面的示例运行。
For an example with a valid 有关有效from field, see Perform a Single Equality Join with $lookup.from字段的示例,请参阅使用$lookup执行单个相等连接。
C#
The C# examples on this page use the 本页上的C#示例使用Atlas示例数据集中的sample_mflix database from the Atlas sample datasets. sample_mflix数据库。To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB .NET/C# Driver documentation.要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB .NET/C#驱动程序文档中的入门。
The following 以下Movie class models the documents in the sample_mflix.movies collection:Movie类对sample_mflix.movies集合中的文档进行建模:
public class Movie
{
public ObjectId Id { get; set; }
public int Runtime { get; set; }
public string Title { get; set; }
public string Rated { get; set; }
public List<string> Genres { get; set; }
public string Plot { get; set; }
public ImdbData Imdb { get; set; }
public int Year { get; set; }
public int Index { get; set; }
public string[] Comments { get; set; }
[]
public DateTime LastUpdated { get; set; }
}
Note
ConventionPack for Pascal CasePascal大小写的约定包
The C# classes on this page use Pascal case for their property names, but the field names in the MongoDB collection use camel case. To account for this difference, you can use the following code to register a 此页面上的C#类使用Pascal大小写作为其属性名,但MongoDB集合中的字段名使用驼峰大小写。为了解释这种差异,您可以在应用程序启动时使用以下代码注册ConventionPack when your application starts:ConventionPack:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);The following 以下Comment class models the documents in the sample_mflix.comments collection:Comment类对sample_mflix.comments集合中的文档进行建模:
public class Comment
{
public Guid Id { get; set; }
[]
public Guid MovieId { get; set; }
public string Text { get; set; }
}
To use the MongoDB .NET/C# driver to add a 要使用MongoDB NET/C#驱动程序向聚合管道添加$lookup stage to an aggregation pipeline, call the Lookup() method on a PipelineDefinition object.$lookup阶段,请在PipelineDefinition对象上调用Lookup()方法。
The following example creates a pipeline stage that performs a left outer join between the 以下示例创建了一个管道阶段,该阶段在movies and comments collections. The code joins the Id field from each Movie document to the MovieId field in the Comment documents. The comments for each movie are stored in a field named Comments in each Movie document.movies和comments集合之间执行左外连接。该代码将每个Movie文档的Id字段连接到Comment文档中的MovieId字段。每部电影的评论都存储在每个Movie文档中名为Comments 的字段中。
var commentCollection = client
.GetDatabase("aggregation_examples")
.GetCollection<Comment>("comments");
var pipeline = new EmptyPipelineDefinition<Movie>()
.Lookup<Movie, Movie, Comment, Movie>(
foreignCollection: commentCollection,
localField: m => m.Id,
foreignField: c => c.MovieId,
@as: m => m.Comments);Node.js
The Node.js examples on this page use the 本页上的Node.js示例使用Atlas示例数据集中的sample_mflix database from the Atlas sample datasets. sample_mflix数据库。To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see Get Started in the MongoDB Node.js driver documentation.要了解如何创建免费的MongoDB Atlas集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门。
To use the MongoDB Node.js driver to add a 要使用MongoDB Node.js驱动程序向聚合管道添加$lookup stage to an aggregation pipeline, use the $lookup operator in a pipeline object.$lookup阶段,请在管道对象中使用$lookup运算符。
The following example creates a pipeline stage that performs a left outer join between the 以下示例创建了一个管道阶段,该阶段在movies and comments collections. movies和comments集合之间执行左外连接。The code joins the 该代码将每个_id field from each movie document to the movie_id field in the comment documents. movie文档的_id字段与评论文档中的movie_id字段连接起来。The comments field stores the comments for each movie in each movie document. The example then runs the aggregation pipeline:comments字段存储每个movie文档中每个电影的评论。然后,该示例运行聚合管道:
const pipeline = [
{
$lookup: {
from: "comments",
localField: "_id",
foreignField: "movie_id",
as: "comments"
}
}
];
const cursor = collection.aggregate(pipeline);
return cursor;