定义
注意
本页介绍了 $merge 阶段,它将聚合管道结果输出到集合中。有关将多个文档合并为单个文档的 $mergeObjects 运算符,请参阅 $mergeObjects。
$merge将聚合管道的结果写入指定的集合。
$merge操作符必须是管道的最后一个阶段。$merge阶段:可以输出到相同或不同数据库中的集合。
可以输出到正在聚合的同一集合。有关更多信息,请参阅输出到正在聚合的同一集合。。
如果输出集合不存在,则创建一个新集合。
可将结果(插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档)并入现有集合。
可输出到分片集合。输入集合也可以是分片的。
$out$merge$out有关与 阶段(也将聚合结果输出到集合)的比较,请参阅 和 比较。
兼容性
可以使用 $merge 查找托管在以下环境中的部署:
- MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
$merge 通过以下语法实现:
{ $merge: { into: <collection> -or- { db: <db>, coll: <collection> }, on: <identifier field> -or- [ <identifier field1>, ...], // Optional let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
例如:
{ $merge: { into: "myOutput", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
如果使用了 $merge 的所有默认选项(包括写入同一数据库中的集合),则可使用简化形式:
{ $merge: <collection> } // Output collection is in the same database
$merge 阶段采用包含以下字段的文档:
字段 | 说明 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
可选。充当文档唯一标识符的一个或多个字段。标识符决定结果文档是否与输出集合中的现有文档相匹配。指定以下任一项:
对于指定的一个或多个字段:
on 的默认值取决于输出集合:
| |||||||||||
可选。如果结果文档与集合中的现有文档具有相同的指定字段值,则 您可以指定以下任一项:
| |||||||||||
可选。指定在 WhenMatched 管道 中使用的变量。 指定包含变量名和值表达式的文档: 如果未指定,默认为 要访问 whenMatched 管道中的变量,请执行以下操作: 以 有关示例,请参阅使用变量自定义合并。 | |||||||||||
Considerations
_id 字段生成
如果聚合管道结果中的文档中不存在 _id 字段,则 $merge 阶段会自动生成该字段。
例如,在以下聚合管道中,$project 从传递给 $merge 的文档中排除 _id 字段。当 $merge 将这些文档写入 "newCollection" 时,$merge 会生成一个新的 _id 字段和值。
db.movies.aggregate( [ { $project: { _id: 0 } }, { $merge : { into : "newCollection" } } ] )
如果输出集合不存在,则创建一个新集合
如果指定的输出集合不存在,则 $merge 操作会创建一个新集合。
当
$merge将第一个文档写入集合时,输出集合就已创建,且立即可见。如果聚合失败,则在错误发生之前,
$merge完成的任何写入都不会回滚。
如果输出集合不存在,则$merge 要求标识符为_id 字段。要为不存在的集合使用不同的on 字段值,可以先在所需字段上创建唯一索引来创建集合。示例,如果输出集合newDailyCommentCount 不存在,而您想将commentDate 字段指定为 on 标识符:
db.newDailyCommentCount.createIndex( { commentDate: 1 }, { unique: true } ) db.comments.aggregate( [ { $match: { date: { $gte: new Date("2002-01-01"), $lt: new Date("2002-02-01") } } }, { $group: { _id: { $dateToString: { format: "%Y-%m-%d", date: "$date" } }, count: { $sum: 1 } } }, { $project: { _id: 0, commentDate: { $toDate: "$_id" }, count: 1 } }, { $merge : { into : "newDailyCommentCount", on: "commentDate" } } ] )
输出到分片集合
$merge 阶段可输出到分片集合。当输出集合为分片集合时,$merge 使用 _id 字段和所有分片键字段作为默认的on标识符。如果覆盖此默认值,on 标识符则须包含所有分片键字段:
{ $merge: { into: "<shardedColl>" or { db:"<sharding enabled db>", coll: "<shardedColl>" }, on: [ "<shardkeyfield1>", "<shardkeyfield2>",... ], // Shard key fields and any additional fields let: <variables>, // Optional whenMatched: <replace|keepExisting|merge|fail|pipeline>, // Optional whenNotMatched: <insert|discard|fail> // Optional } }
例如,使用 sh.shardCollection() 方法创建新的分片集合 moviesByYearAndRating,其中 rated 字段作为分片键。
sh.shardCollection( "sample_mflix.moviesByYearAndRating", // Namespace of the collection to shard { rated: 1 }, // Shard key );
moviesByYearAndRating集合将包含按年份(year 字段)和内容分级(分片键)列出的电影统计信息文档;具体来说,on 标识符为["year", "rated"] (字段的顺序无关紧要)。由于$merge 1需要唯一索引,其中的键与标识符字段相对应,因此请创建唯一索引(字段的顺序无关紧要):[]
db.moviesByYearAndRating.createIndex( { rated: 1, year: 1 }, { unique: true } )
通过创建分片集合 moviesByYearAndRating 和唯一索引后,可以使用 $merge 将聚合结果输出到此集合,匹配 [ "year", "rated" ],如下例所示:
db.movies.aggregate( [ { $match: { rated: { $ne: null }, year: { $ne: null } } }, { $group: { _id: { year: "$year", rated: "$rated" }, movieCount: { $sum: 1 } } }, { $project: { _id: 0, year: "$_id.year", rated: "$_id.rated", movieCount: 1 } }, { $merge: { into: "moviesByYearAndRating", "on": [ "year", "rated" ], whenMatched: "replace", whenNotMatched: "insert" } } ] )
| [1] | 在传递 在上一个示例中,由于 |
替换文档 ($merge) 与替换集合 ($out)
$merge 如果聚合结果包含根据...规范匹配的一个或多个文档,则可以替换输出集合中的现有文档。因此,如果聚合结果包括集合中所有现有文档的匹配文档并且您在$merge 中指定“替换”,则 可以替换现有集合中的所有文档。 for whenMatched。
但是,在不考虑聚合结果的情况下,如果要替换现有集合,请使用 $out。
现有文档和 _id 以及分片键值
如果 $merge 导致现有文档的 _id 值发生变化,则会出现 $merge 错误。
唯一索引约束
如果$merge 在字段上使用的唯一索引在聚合过程中被删除,则无法保证聚合会被终止。如果继续聚合,则无法保证文档中没有重复的on 字段值。
如果 $merge 尝试写入的文档违反输出集合上的任何唯一索引,则操作会产生错误。例如:
插入一个不匹配的文档,该文档违反了唯一索引(非 on 字段的索引)。
模式验证
如果您的集合使用模式验证并将 validationAction 设置为 error,则插入无效文档或使用 $merge 更新具有无效值的文档会抛出 MongoServerError,并且该文档不会写入目标集合。如果有多个无效文档,则只有出现的第一个无效文档会引发错误。所有有效文档都写入目标集合,所有无效文档都会写入失败。
whenMatched 管道行为
$merge 在满足以下所有条件时,将文档直接插入到输出集合中:
whenMatched 的值为聚合管道。
whenNotMatched 的值为
insert。输出集合中没有匹配的文档。
$merge 和 $out 比较
随着$merge的引入,MongoDB 提供两个阶段,即 $merge 和 $out,用于将聚合管道的结果写入集合:
$merge | |
|---|---|
|
|
|
|
|
|
|
|
|
|
输出到正在聚合的同一集合
限制
限制 | 说明 |
|---|---|
聚合管道不能在事务中使用 | |
聚合管道不能使用 | |
视图定义 | 视图定义不能包括 |
| |
| |
|
|
|
|