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

$ 项目 (聚合阶段)

$project

将带所请求字段的文档传递至管道中的下个阶段。指定的字段可以是输入文档中的已有字段或新计算的字段。

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

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

$project 阶段具有以下原型形式:

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

$project 采用的文档可以指定包含字段、抑制 _id 字段、添加新字段以及重置现有字段的值。您也可以指定排除字段。

$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字段。要从$project阶段排除 _id字段,请在投影 document 中将 _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 字段 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 ] }]

如需了解有关常见聚合任务的更多信息和详细说明,请参阅完整聚合管道教程。

要进一步了解此页面上的方法,请参阅以下指南: