定义
$addFields为文档添加新字段。
$addFields输出文档包含输入文档中的所有现有字段和新添加的字段。$addFields阶段等效于$project阶段,后者明确指定输入文档中的所有现有字段并添加新字段。注意
您还可以使用
$set阶段,它是$addFields的别名。
兼容性
可以使用 $addFields 查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
该阶段采用以下语法:
{ $addFields: { <newField>: <expression>, ... } }
指定要添加的每个字段的名称,并将其值设立为聚合表达式或空对象。有关表达式的更多信息,请参阅表达式。
重要
如果新字段名称与现有字段名称(包括 _id)相同,$addFields 将用指定表达式的值覆盖该字段的现有值。
行为
$addFields将新字段附加到现有文档。可以在聚合操作中包含一个或多个$addFields阶段。$addFields接受对象的嵌入,您可以将值设置为聚合表达式或空对象。例如,接受以下嵌套对象:{$addFields: { a: { b: { } } } } 要将一个或多个字段添加到嵌入式文档(包括数组中的文档),请使用点表示法。请参阅示例。
要使用
$addFields向现有数组字段添加元素,请与$concatArrays一起使用。请参阅示例。
示例
本页上的示例使用 sample_mflix示例数据集 中的数据。有关如何将此数据集加载到自管理MongoDB 部署中的详细信息,请参阅加载示例数据集。如果对示例数据库进行了任何修改,则可能需要删除并重新创建数据库才能运行本页上的示例。
使用两个 $addFields 阶段
以下操作使用两个 $addFields 阶段,首先将运行时间转换为小时数,然后按每小时 0.50 美元计算许可费用:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { runtimeHours: { $floor: { $divide: [ "$runtime", 60 ] } }, ratingOutOf100: { $multiply: [ "$imdb.rating", 10 ] } } }, { $addFields: { licenseFeeUSD: { $multiply: [ "$runtimeHours", 0.50 ] } } } ] )
[ { _id: ..., title: 'Baseball', runtime: 1140, runtimeHours: 19, licenseFeeUSD: 9.5 }, { _id: ..., title: 'Centennial', runtime: 1256, runtimeHours: 20, licenseFeeUSD: 10 } ] ...
为嵌入式文档添加字段
使用点符号为嵌入式文档添加新字段。
以下聚合操作将 certified字段添加到每部电影的嵌入式 imdb文档中:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { "imdb.certified": true } } ] )
[ { _id: ..., title: 'Baseball', imdb: { certified: true, '...': '...' } }, { _id: ..., title: 'Centennial', imdb: { certified: true, '...': '...' } } ] ...
覆盖现有字段
在 $addFields 操作中指定现有字段名称会导致原始字段被替换。
以下 $addFields 操作会覆盖 runtime字段以添加 15 分钟:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { runtime: { $add: [ "$runtime", 15 ] } } } ] )
[ { _id: ..., title: 'Baseball', runtime: 1155 }, { _id: ..., title: 'Centennial', runtime: 1271 } ] ...
您还可以将一个字段替换为另一个字段。以下操作将 _id 设置为电影的标题,并将 title字段替换为电影的主节点 (primary node in the replica set)类型:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { _id: "$title", title: { $arrayElemAt: [ "$genres", 0 ] } } } ] )
[ { _id: 'Baseball', title: 'Documentary' }, { _id: 'Centennial', title: 'Action' } ] ...
向数组添加元素
可以使用 $addFields 和 $concatArrays 表达式向现有数组字段添加元素。以下操作将 Epic 追加到标题为 Centennial 的电影的 genres数组中:
db.movies.aggregate( [ { $match: { title: "Centennial" } }, { $addFields: { genres: { $concatArrays: [ "$genres", [ "Epic" ] ] } } } ] )
[ { _id: ..., title: 'Centennial', genres: [ 'Action', 'Adventure', 'Drama', 'Epic' ] } ] ...
removeFields
您可以使用 $addFields 和 $$REMOVE 变量来删除文档字段。
以下操作使用 $addFields删除附带 $$REMOVE 变量的 plot字段:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { plot: "$$REMOVE" } } ] )
[ { _id: ..., title: 'Baseball', runtime: 1140 }, { _id: ..., title: 'Centennial', runtime: 1256 } ] ...
您也可以使用 $$REMOVE 有条件地删除字段。例如,以下聚合从 rated 为 null 的文档中删除 rated 字段:
db.movies.aggregate( [ { $match: { runtime: { $gt: 1000 } } }, { $addFields: { rated: { $ifNull: [ "$rated", "$$REMOVE" ] } } } ] )
[ { _id: ..., title: 'Baseball', rated: 'TV-PG' }, { _id: ..., title: 'Centennial' } ] ...
本页上的 Node.js 示例使用 Atlas 示例数据集中的 sample_mflix数据库。要学习如何创建免费的MongoDB Atlas 集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门。
要使用MongoDB Node.js驱动程序将 $addFields 阶段添加到聚合管道,请在管道对象中使用 $addFields操作符。
以下示例创建了一个管道阶段,该阶段向每个电影文档添加一个 totalReviews字段,其中包含电影的评论总数。然后,该示例运行聚合管道:
const pipeline = [ { $addFields: { totalReviews: { $add: ["$imdb.votes", "$tomatoes.viewer.numReviews"] } } } ]; const cursor = collection.aggregate(pipeline); return cursor;
提示
与 $project 的比较
您可以使用 $addFields 或 $project 阶段删除文档字段。最佳方法取决于您的管道以及您希望保留多少原始文档。
有关在 $project 阶段使用 $$REMOVE 的示例,请参阅有条件地排除字段。