Make the MongoDB docs better! We value your opinion. Share your feedback for a chance to win $100.
Click here >
Docs 菜单
Docs 主页
/ /

$lookup(聚合阶段)

$lookup

在版本8.0中进行了更改

同一数据库中的一个集合执行左外连接,以便从外部集合中过滤文档进行处理。$lookup 阶段会为每个输入文档添加一个新的数组字段。新数组字段包含来自外部集合的匹配文档。$lookup 阶段会将这些重塑后的文档传递给下一阶段。

从 MongoDB 5.1 开始,可以将 $lookup 与分片集合一起使用。

要组合来自两个不同集合的元素,请使用 $unionWith 管道阶段。

重要

过多使用 $lookup 可能会降低查询性能。为了减少对 $lookup 的依赖,请考虑使用嵌入式数据模型将相关数据存储在单个集合中。

有关 $lookup 性能的详细信息,请参阅性能注意事项。

可以使用 $lookup 查找托管在以下环境中的部署:

  • MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务

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

$lookup 接受包含如下字段的文档:

字段
必要性
说明

必需

同一个数据库中指定待联接到本地集合的外部集合。

在某些边缘情况下,可以使用 pipeline 替换 from,并将 $documents 作为第一阶段。有关示例,请参阅在 $lookup 阶段中使用 $documents 阶段。

从 MongoDB 5.1 开始,from 集合可以分片。

如果指定了 pipeline,则为可选

指定输入到$lookup 阶段的文档中的字段。$lookuplocalFieldforeignFieldfrom 与 集合文档中的 执行等值匹配。如果输入文档不包含localField ,则出于匹配目的,$lookup 会将该字段视为具有null 值。

如果指定了 pipeline,则为可选

指定外部文档的 foreignField 对本地文档的 localField 执行等值匹配。

如果外部文档不包含foreignField 值,则 将使用$lookup null值进行匹配。

Optional

指定在管道阶段中使用的变量。使用变量表达式访问本地集合文档中的字段,这些文档输入到 pipeline

要引用管道阶段中的变量,请使用 "$$<variable>"事务语法。

let 变量可由管道中的阶段访问,包括嵌套在$lookup 中的其他pipeline 阶段。

  • $match 阶段需要使用 $expr 操作符来访问变量。$expr 操作符允许在 $match 语法中使用聚合表达式。

    位于 $eq$expr操作符中的 、$lt$gte$lte$gt 和 比较操作符可以使用from $lookup阶段中引用的 集合上的索引。限制:

    • 索引只能用于字段和常量之间的比较,因此 let 操作数必须解析为常量。

      示例,$a 和常量值之间的比较可以使用索引,但 $a$b 之间的比较不能使用索引。

    • let 操作数解析为空值或缺失值时,索引不用于比较。

    • 不使用 多键部分稀疏 索引。

  • 管道中的其他(非$match )阶段不需要 $expr操作符符来访问权限变量。

如果指定了 localFieldforeignField,则为可选

指定在外部集合上运行的 pipelinepipeline 返回外部集合的文档。如要返回所有文档,请指定一个空的 pipeline: []

pipeline不能包括$out 或 阶段。从$merge v6.0 开始,pipeline 可以包含MongoDB Search$search 阶段作为管道内的第一阶段。要学习;了解更多信息,请参阅MongoDB搜索支持。

pipeline 无法访问输入文档中的字段。可以使用 let 选项定义文档字段的变量,然后在 pipeline 阶段引用这些变量。

要引用管道阶段中的变量,请使用 "$$<variable>"事务语法。

let 变量可由管道中的阶段访问,包括嵌套在$lookup 中的其他pipeline 阶段。

  • $match 阶段需要使用 $expr 操作符来访问变量。$expr 操作符允许在 $match 语法中使用聚合表达式。

    位于 $eq$expr操作符中的 、$lt$gte$lte$gt 和 比较操作符可以使用from $lookup阶段中引用的 集合上的索引。限制:

    • 索引只能用于字段和常量之间的比较,因此 let 操作数必须解析为常量。

      示例,$a 和常量值之间的比较可以使用索引,但 $a$b 之间的比较不能使用索引。

    • let 操作数解析为空值或缺失值时,索引不用于比较。

    • 不使用 多键部分稀疏 索引。

  • 管道中的其他(非$match )阶段不需要 $expr操作符符来访问权限变量。

必需

指定要添加到输入文档中的新数组字段的名称。新数组字段包含来自 from 集合的匹配文档。如果输入文档中已存在指定的名称,现有字段将被重写

如要在输入文档中的字段与外部集合的文档中的字段之间执行等值匹配,$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>
}
}

注意

在此示例中,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 支持:

  • 在外部集合上执行管道。

  • 多个联接条件。

  • 关联和不关联子查询。

在MongoDB中,不相关子查询意味着每个输入文档都将返回相同的结果。相关子查询是处于 阶段的 管道 $lookup,它使用本地或input 集合的字段返回与每个传入文档相关的结果。

注意

从 MongoDB 5.0 开始,对于包含 $sample 阶段、$sampleRate 操作符或 $rand 操作符的 $lookup 管道阶段中的非关联子查询,如果重复此子查询,此子查询总是会再次运行。以前,根据子查询输出大小,要么缓存子查询输出,要么再次运行子查询。

MongoDB 相关子查询与 SQL 相关子查询类似,其中内部查询引用外部查询值。SQL 不相关子查询不引用外部查询值。

MongoDB 5.0 还支持简洁关联子查询

要对两个集合执行关联和非关联子查询,并执行除单一等值匹配外的其他联接条件,请使用此 $lookup 语法:

{
$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>
);

请参阅如下示例:

从MongoDB 8.1 开始,您可以在 $lookup 阶段引用多个加密集合。但是,$lookup 不支持:

  • 使用加密字段作为 localFieldforeignField 中的联接字段。

    注意

    对于使用 客户端字段级加密的驱动程序,只有在执行自连接操作时才能使用加密字段作为连接字段。

  • 使用加密大量中的任何字段。如果大量包含任何加密元素,则视为加密。

    • 示例,除非使用客户端字段级加密和 $lookup字段,否则不能使用 操作生成的 as$unwind as数组中的任何字段。

如果执行的聚合涉及多个视图(如使用 $lookup$graphLookup),则这些视图必须具有相同的排序规则

您不能将 $out$merge 阶段包含到 $lookup 阶段中。换言之,在指定外部集合的管道时,您不能在 pipeline 字段中包含任何阶段。

{
$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>
}
}

从MongoDB6.0 开始,您可以在 管道中指定MongoDB搜索$search$searchMeta $lookup阶段来搜索Atlas 集群上的集合。$search$searchMeta 阶段必须是$lookup 管道内的第一阶段。

示例,当您在外部集合上连接条件和子查询或使用简洁事务语法运行关联子查询时,您可以在管道内指定 $search$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": [{
"$search": {
"<operator>": {
<operator-specification>
}
},
...
}]
}
}]
[{
"$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>
}
},
...
}]
}
}]

要查看$lookup$search 的示例,请参阅MongoDB Search 教程使用 $lookup 运行MongoDB Search $ 搜索查询。

从 MongoDB 5.1 开始,可以在 $lookup 阶段的 from 参数中指定分片集合

从 MongoDB 8.0 开始,您可以在事务内使用 $lookup 阶段,并以分片集合为目标。

从版本 6.0 开始,MongoDB 可以使用基于槽的执行查询引擎来执行 $lookup 阶段,前提是在此管道中,前面的所有阶段也可由基于槽的执行引擎执行,并且以下条件都不成立:

  • $lookup 操作在外键集合上执行管道。要查看此类操作的示例,请参阅外部集合上的连接条件和子查询。

  • $lookuplocalFieldforeignField 指定数字成分。例如:{ localField: "restaurant.0.review" }

  • 管道中任何 $lookupfrom 字段指定视图或分片集合。

有关更多信息,请参阅 $lookup 优化

$lookup 性能取决于执行的操作类型。请参阅下表了解不同 $lookup 操作的性能注意事项。

$lookup 操作
性能考虑因素
  • $lookup 当外部集合在 foreignField 上包含索引时,使用单个联接执行等值匹配的操作通常具有较好的性能。

    重要提示:如果 foreignField 上的支持索引不存在,使用单个联接执行等值匹配的 $lookup 操作可能具有较差的性能。

  • $lookup 在内部管道可以引用外部集合的索引时,包含不相关子查询的操作具有较好的性能。

  • MongoDB 只需要在缓存查询之前运行一次 $lookup 子查询,因为源和外部集合之间没有关系。子查询不基于源集合中的任何值。此行为可提高后续执行 $lookup 操作的性能。

  • $lookup 在以下条件适用时,包含相关子查询的操作通常具有较好的性能:

    • 该外部集合包含 foreignField 上的一个索引。

    • 外部集合包含引用内部管道的索引。

  • 如果管道将大量文档传递给 $lookup 查询,以下策略可能会提高性能:

    • 减少 MongoDB 传递给 $lookup 查询的文档数量。例如,在 $match 阶段设定更严格的筛选器。

    • $lookup 子查询的内部管道作为单独查询运行,并使用 $out 创建临时集合。 然后,使用单个联接运行等值匹配。

    • 重新考虑数据的模式,以确保它对于使用案例来说是最佳的。

有关一般性能策略,请参阅索引策略查询优化

本页上的示例使用 sample_mflix示例数据集中的数据。有关如何将此数据集加载到自管理MongoDB 部署中的详细信息,请参阅加载示例数据集。如果对示例数据库进行了任何修改,则可能需要删除并重新创建数据库才能运行本页上的示例。

以下聚合操作首先将 movies集合筛选为 runtime 大于 1000 的电影,然后在 _idmovie_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
);

有关更多信息,请参阅等值匹配性能注意事项

如果 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'
}
]
}
]

$mergeObjects 操作符将多个文档合并成一个文档。

以下操作使用$lookup 连接movies 集合与comments 集合,然后使用$mergeObjects 中的$replaceRoot 将第一个评论文档与电影文档合并:

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() 方法的本地集合中的字段,并引用外部集合中的字段。这样即可在两个集合之间执行一个关联子查询。

MongoDB 5.0 支持简洁关联子查询

如下示例:

  • 使用 _idmovie_id 字段连接 moviescomments 集合。

  • 筛选评论以仅包含在电影发布年份之后发布的评论。

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
);

放置在 $expr 操作符上的 $eq$lt$lte$gt$gte 比较操作符可以使用 $lookup 阶段引用的 from 集合上的索引。限制:

  • 索引只能用于字段和常量之间的比较,因此 let 操作数必须解析为常量。

    示例,$a 和常量值之间的比较可以使用索引,但 $a$b 之间的比较不能使用索引。

  • let 操作数解析为空值或缺失值时,索引不用于比较。

  • 不使用 多键部分稀疏 索引。

例如,如果索引 { movie_id: 1 } 存在于 comments 集合上:

  • comments.movie_id 字段上的等值匹配使用索引。

提示

聚合管道 $lookup 阶段可以在外部集合上执行管道,这样即可执行非关联子查询。非关联子查询不引用本地文档字段。

注意

从 MongoDB 5.0 开始,对于包含 $sample 阶段、$sampleRate 操作符或 $rand 操作符的 $lookup 管道阶段中的非关联子查询,如果重复此子查询,此子查询总是会再次运行。以前,根据子查询输出大小,要么缓存子查询输出,要么再次运行子查询。

以下操作将 users集合与 movies集合中运行时间大于 1000 分钟的电影连接起来:

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
);

如需详细了解,请参阅非关联子查询性能注意事项。

版本 5.0 中的新增功能

从 MongoDB 5.0 开始,聚合管道 $lookup 阶段支持简洁关联子查询语法,该语法改进了集合之间的联接。新的简洁语法取消了在 $match 阶段对 $expr 操作符内的外部和本地字段进行等值匹配的要求。

如下示例:

  • moviescomments通过将本地字段 _id与外部字段 进行匹配来连接 和movie_id 集合。在运行pipeline 之前执行匹配。

  • 筛选评论,仅包含在电影发布年份之后发布的评论,可分别使用 $$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')
}
]
}
]

此示例使用 5.0 之前的 MongoDB 版本中较旧的详细事务语法,并返回与上一个简洁示例相同的结果:

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 开始,会验证 $lookup$unionWith 内子管道中的命名空间,以确保正确使用 fromcoll 字段:

  • 对于 $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 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; }
[BsonElement("lastupdated")]
public DateTime LastUpdated { get; set; }
}

注意

用于 Pascal Case 的 ConventionPack

此页面上的 C# 类在其属性名称中使用 Pascal 命名法,而 MongoDB 集合中的字段名称则使用 camel 命名法。为了解决这种差异,可以在应用程序启动时使用以下代码注册一个 ConventionPack

var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

以下 Comment 类对 sample_mflix.comments 集合中的文档进行建模:

public class Comment
{
public Guid Id { get; set; }
[BsonElement("movie_id")]
public Guid MovieId { get; set; }
public string Text { get; set; }
}

要使用MongoDB .NET/C# 驱动程序将 $lookup 阶段添加到聚合管道,请对 PipelineDefinition 对象调用 Lookup() 方法。

以下示例创建了一个管道阶段,用于在 moviescomments 集合之间执行左外连接。该代码将每个 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 示例使用 Atlas 示例数据集中的 sample_mflix数据库。要学习如何创建免费的MongoDB Atlas 集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门

要使用MongoDB Node.js驱动程序将 $lookup 阶段添加到聚合管道,请在管道对象中使用 $lookup操作符。

以下示例创建了一个管道阶段,该阶段在 moviescomments 集合之间执行左外连接。该代码将每个 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;

后退

$listSessions

获得技能徽章

免费掌握“关系到文档模型”!

了解详情

在此页面上