对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

$ 项目 (聚合阶段)

$project

将带有请求字段的文档传递到管道的下一阶段。指定的字段可以是输入文档中的现有字段,也可以是新的计算字段。

$project 可以:

  • 包括输入文档中的字段。

  • 抑制 _id字段。

  • 添加新字段或重置现有字段的值。

  • 从输入文档中排除字段。

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

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

$project 采用以下形式:

{ $project: { <specification(s)> } }

$project 规范具有以下形式:

形式
说明

<field>: <1 or true>

指定包含字段。非零整数也被视为 true。

_id: <0 or false>

指定抑制 _id字段。

要有条件地排除字段,请改用 REMOVE 变量。有关详细信息,请参阅有条件地排除字段。

<field>: <expression>

添加新字段或重置现有字段的值。

如果表达式的计算结果为 $$REMOVE,则在输出中排除该字段。有关详细信息,请参阅有条件地排除字段。

<field>: <0 or false>

指定排除字段。

要有条件地排除字段,请改用 REMOVE 变量。有关详细信息,请参阅有条件地排除字段。

如果指定排除 _id 以外的字段,则不能使用任何其他 $project 规范。此限制不适应用使用 REMOVE 变量对字段进行条件排除。

要排除字段,还可以使用 $unset 阶段。

  • 默认下,输出文档包含 _id字段。要包含输入文档中的其他字段,请在 $project 中明确指定这些字段。

  • 如果指定包含文档中不存在的字段,$project 将忽略该字段包含,并且不会将该字段添加到文档中。

默认下,_id字段包含在输出文档中。要从输出文档中排除 _id字段,您必须显式抑制 $project 中的 _id字段。

如果排除一个字段,则所有其他字段都会出现在输出文档中。

{ $project: { "<field1>": 0, "<field2>": 0, ... } } // Return all but the specified fields

如果排除 _id 以外的字段,则无法使用其他 $project 规范形式。如果排除字段,则无法同时指定包含字段、重置现有字段的值或添加新字段。此限制不适应用使用 REMOVE 变量对字段进行条件排除。

要排除字段,也可以使用 $unset。

您可以在聚合表达式中使用变量 REMOVE 有条件地抑制字段。有关示例,请参阅有条件地排除字段。

注意

MongoDB 还提供 $addFields 向文档添加新字段。

要添加新字段或重置现有字段的值,请指定字段名称并将其值设立为表达式。有关表达式的更多信息,请参阅表达式。

要将字段设立为数字或布尔文字,而不是解析为文字的表达式,请使用 $literal操作符。否则,$project 将该字面量视为包含或排除字段 的标志。

有效地重命名字段的方式:指定新字段并将其值设置为现有字段的字段路径。

$project 阶段支持使用方括号 [] 直接创建新的大量字段。如果指定文档中不存在的大量字段,则该操作会将 null 替换为该字段的值。有关示例,请参阅投影新的数组字段。

不能将大量索引与 $project 阶段一起使用。

要在嵌入式文档中项目、添加或重置字段,可以使用点表示法:

"contact.address.country": <1 or 0 or expression>

您还可以嵌套字段:

contact: { address: { country: <1 or 0 or expression> } }

嵌套字段时,不能在嵌入式文档中使用点表示法来指定字段。示例,contact: { "address.country": <1 or 0 or expression> } 无效。

不能在同一投影中同时指定嵌入式文档和嵌入式文档中的字段。

以下 $project 阶段失败并显示 Path collision 错误,因为它尝试项目嵌入式 contact文档和 contact.address.country字段:

{ $project: { contact: 1, "contact.address.country": 1 } }

无论指定父字段和嵌入式字段的顺序如何,都会发生错误。以下 $project 失败并出现相同的错误:

{ $project: { "contact.address.country": 1, contact: 1 } }

当您使用 $project 阶段时,它通常应该是管道中的最后一个阶段,用于指定要返回给客户端的字段。

在管道的开头或中间使用 $project 阶段来减少传递到后续管道阶段的字段数量不太可能提高性能,因为数据库会自动执行此优化。

如果向 $project 阶段传递了空文档,MongoDB会返回错误。

示例,以下管道会返回错误:

db.myCollection.aggregate( [ {
$project: { }
} ] )

不能将大量索引与 $project 阶段一起使用。

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

以下 $project 阶段仅包括 _id、title 和 rated 字段:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { title: 1, rated: 1 } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
title: 'The Great Train Robbery',
rated: 'TV-G'
}
]

MongoDB默认包含 _id字段。要将 _id字段从 $project 阶段排除,请在投影文档中将 _id字段设立为 0。

以下 $project 阶段不包括 _id字段,但包括 title 和 rated 字段:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project : { _id: 0, title : 1, rated : 1 } },
{ $limit: 1 }
] )
[ { title: 'The Great Train Robbery', rated: 'TV-G' } ]

以下 $project 阶段会从输出中排除 rated字段:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project : { "rated": 0 } },
{ $limit: 1 }
] )

或者,使用$unset阶段排除字段。

以下 $project 阶段会从输出中排除 imdb.id 和 type 字段:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { "imdb.id": 0, "type": 0 } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
plot: 'A group of bandits stage a brazen train hold-up, only to find a determined posse hot on their heels.',
genres: [ 'Short', 'Western' ],
runtime: 11,
cast: [
'A.C. Abadie',
"Gilbert M. 'Broncho Billy' Anderson",
'George Barnes',
'Justus D. Barnes'
],
poster: 'https://m.media-amazon.com/images/M/MV5BMTU3NjE5NzYtYTYyNS00MDVmLWIwYjgtMmYwYWIxZDYyNzU2XkEyXkFqcGdeQXVyNzQzNzQxNzI@._V1_SY1000_SX677_AL_.jpg',
title: 'The Great Train Robbery',
fullplot: "Among the earliest existing films in American cinema - notable as the first film that presented a narrative story to tell - it depicts a group of cowboy outlaws who hold up a train and rob the passengers. They are then pursued by a Sheriff's posse. Several scenes have color included - all hand tinted.",
languages: [ 'English' ],
released: ISODate('1903-12-01T00:00:00.000Z'),
directors: [ 'Edwin S. Porter' ],
rated: 'TV-G',
awards: { wins: 1, nominations: 0, text: '1 win.' },
lastupdated: '2015-08-13 00:27:59.177000000',
year: 1903,
imdb: { rating: 7.4, votes: 9847 },
countries: [ 'USA' ],
tomatoes: {
viewer: { rating: 3.7, numReviews: 2559, meter: 75 },
fresh: 6,
critic: { rating: 7.6, numReviews: 6, meter: 100 },
rotten: 0,
lastUpdated: ISODate('2015-08-08T19:16:10.000Z')
},
num_mflix_comments: 0
}
]

或者,您可以在文档中嵌套排除规范:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { "imdb": { "id": 0 }, "type" : 0 } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
plot: 'A group of bandits stage a brazen train hold-up, only to find a determined posse hot on their heels.',
genres: [ 'Short', 'Western' ],
runtime: 11,
cast: [
'A.C. Abadie',
"Gilbert M. 'Broncho Billy' Anderson",
'George Barnes',
'Justus D. Barnes'
],
poster: 'https://m.media-amazon.com/images/M/MV5BMTU3NjE5NzYtYTYyNS00MDVmLWIwYjgtMmYwYWIxZDYyNzU2XkEyXkFqcGdeQXVyNzQzNzQxNzI@._V1_SY1000_SX677_AL_.jpg',
title: 'The Great Train Robbery',
fullplot: "Among the earliest existing films in American cinema - notable as the first film that presented a narrative story to tell - it depicts a group of cowboy outlaws who hold up a train and rob the passengers. They are then pursued by a Sheriff's posse. Several scenes have color included - all hand tinted.",
languages: [ 'English' ],
released: ISODate('1903-12-01T00:00:00.000Z'),
directors: [ 'Edwin S. Porter' ],
rated: 'TV-G',
awards: { wins: 1, nominations: 0, text: '1 win.' },
lastupdated: '2015-08-13 00:27:59.177000000',
year: 1903,
imdb: { rating: 7.4, votes: 9847 },
countries: [ 'USA' ],
tomatoes: {
viewer: { rating: 3.7, numReviews: 2559, meter: 75 },
fresh: 6,
critic: { rating: 7.6, numReviews: 6, meter: 100 },
rotten: 0,
lastUpdated: ISODate('2015-08-08T19:16:10.000Z')
},
num_mflix_comments: 0
}
]

或者,使用$unset阶段排除字段。

可以在聚合表达式中使用变量 REMOVE 来有条件地隐藏字段。

The following $project stage uses the REMOVE variable to exclude the imdb.votes field if it equals null or is an empty string:

db.movies.aggregate( [
{ $match: { title: "This Is Spinal Tap" } },
{
$project: {
title: 1,
"imdb.rating": 1,
"imdb.id": 1,
"imdb.votes": {
$cond: {
if: { $in: [ "$imdb.votes", [ null, "" ] ] },
then: "$$REMOVE",
else: "$imdb.votes"
}
}
}
},
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1398f29313caabce94a3'),
title: 'This Is Spinal Tap',
imdb: { rating: 8, id: 88258 }
}
]

由于 imdb.votes 在此 document 中为空 string,因此MongoDB会从输出中排除该字段。

提示

与 $addFields 的比较

您可以使用 $addFields 或 $project 阶段删除文档字段。最佳方法取决于您的管道以及您希望保留多少原始文档。

要查看在 $addFields 阶段中使用 $$REMOVE 的示例,请参阅删除字段。

movies集合中的document包含嵌入式 imdbdocument,其中包含 rating、votes 和 id 字段。要仅包含 rating字段从imdb document中,请使用点表示法:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { "imdb.rating": 1 } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
imdb: { rating: 7.4 }
}
]

或者,将包含规范嵌套在 document 中:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { imdb: { rating: 1 } } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
imdb: { rating: 7.4 }
}
]

以下 $project 阶段添加 leadActor 和 releaseYear 字段:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{
$project: {
title: 1,
leadActor: { $arrayElemAt: [ "$cast", 0 ] },
releaseYear: "$year"
}
},
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
title: 'The Great Train Robbery',
leadActor: 'A.C. Abadie',
releaseYear: 1903
}
]

以下操作将 year 和 runtime 字段投影为新 myArray字段中的元素:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { myArray: [ "$year", "$runtime" ] } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
myArray: [ 1903, 11 ]
}
]

如果数组规范包含文档中不存在的字段,则该操作将 null 替换为该字段的值。

示例,对于与上述相同的文档,以下操作将字段 year、runtime 和不存在的字段$someField 投影为新字段myArray 中的元素:

db.movies.aggregate( [
{ $match: { title: "The Great Train Robbery" } },
{ $project: { myArray: [ "$year", "$runtime", "$someField" ] } },
{ $limit: 1 }
] )
[
{
_id: ObjectId('573a1390f29313caabcd42e8'),
myArray: [ 1903, 11, null ]
}
]

有关常见聚合任务的更多信息,请参阅完整的聚合管道教程。

要学习;了解有关此页面上的表达式和变量的更多信息,请参阅: