$out(聚合)
定义
语法
$out
阶段采用以下语法:
$out
可以使用文档来指定输出数据库以及输出集合:{ $out: { db: "<output-db>", coll: "<output-collection>" } } $out
可以采用字符串来仅指定输出集合(即输出到同一数据库中的集合):{ $out: "<output-collection>" } // Output collection is in the same database
重要
您不能将分片集合指定为输出集合。管道的输入集合可以进行分片。要输出到分片集合,请参阅
$merge
(从 MongoDB 4.2 开始提供)。如果修改带 Atlas Search 索引的集合,必须先删除搜索索引,然后重新创建搜索索引。请考虑改用
$merge
。
使用以下项进行比较 $merge
随着版本4.2中引入$merge
, MongoDB 提供了两个阶段$merge
和$out
,用于将聚合管道的结果写入集合。 这两个阶段的功能总结如下:
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
|
行为
$out 读取操作在从节点副本集成员上运行
从 MongoDB5.0 开始,如果集群中的所有节点都将$out
featureCompatibilityVersion 5.0
设置为 或更高版本,并且“ 读取偏好” 设置为从节点,则 可以在副本集从节点上运行。
$out
语句的读取操作发生在从节点上,而写入操作仅发生在主节点上。
并非所有驱动程序版本都支持将$out
操作定位到副本集从节点。 检查驱动程序文档,了解驱动程序何时添加了对在从节点上运行的$out
的支持。
创建新集合
如果集合尚不存在,则$out
操作会创建一个新集合。
在聚合完成之前,集合不可见。如果聚合失败,则 MongoDB 不会创建集合。
替换现有集合
如果$out
操作指定的集合已经存在,则在聚合完成后, $out
阶段将以原子方式将现有集合替换为新的结果集合。 具体来说, $out
操作:
创建临时集合。
将现有集合中的索引拷贝到临时集合。
将文档插入临时集合。
使用
dropTarget: true
调用renameCollection
命令,将 temp 集合重命名为目标集合。
$out
操作不会更改上一个集合中存在的任何索引。 如果聚合失败,则$out
操作不会对预先存在的集合进行更改。
模式验证错误
如果您的 coll
集合使用模式验证且将 validationAction
设置为 error
,则插入带有 $out
的无效文档会引发错误。$out
操作不会对预先存在的集合进行任何更改,并且聚合管道返回的文档不会添加到 coll
集合中。
索引约束
如果管道生成的文档违反任何唯一索引(包括针对原始输出集合的 _id
字段的索引),则管道无法完成。
如果$out
操作修改了具有Atlas Search索引的集合,则必须删除并重新创建Atlas Search索引。 请考虑改用$merge
。
majority
读关注 (read concern)
您可以为包含 $out
阶段的聚合指定读关注级别 "majority"
。
互动 mongodump
mongodump
--oplog
如果客户端在转储进程中发出包含 的聚合管道,则使用$out
将失败。有关更多信息,请参阅mongodump --oplog
。
限制
限制 | 说明 |
---|---|
聚合管道不能使用 $out 输出到时间序列集合。 | |
$lookup 阶段 | |
$facet 阶段 | |
$unionWith 阶段 | |
"linearizable" 读关注 (read concern) |
|
示例
在 test
数据库中,创建包含以下文档的集合 books
:
db.getSiblingDB("test").books.insertMany([ { "_id" : 8751, "title" : "The Banquet", "author" : "Dante", "copies" : 2 }, { "_id" : 8752, "title" : "Divine Comedy", "author" : "Dante", "copies" : 1 }, { "_id" : 8645, "title" : "Eclogues", "author" : "Dante", "copies" : 2 }, { "_id" : 7000, "title" : "The Odyssey", "author" : "Homer", "copies" : 10 }, { "_id" : 7020, "title" : "Iliad", "author" : "Homer", "copies" : 10 } ])
如果 test
数据库尚不存在,则该插入操作将创建该数据库以及 books
集合。
输出到同一数据库
以下聚合操作对 test
数据库中 books
集合中的数据进行透视,从而按作者对书名分组,然后将结果写入同样位于 test
数据库的 authors
集合。
db.getSiblingDB("test").books.aggregate( [ { $group : { _id : "$author", books: { $push: "$title" } } }, { $out : "authors" } ] )
- 第一阶段 (
$group
): $group
阶段按authors
进行分组,并使用$push
将书名添加到books
数组字段:{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] } { "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } - 第二阶段(
$out
): $out
阶段将文档输出到test
数据库中的authors
集合。
要查看输出集合中的文档,运行以下操作:
db.getSiblingDB("test").authors.find()
该集合包含以下文档:
{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } { "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }
输出到其他数据库
$out
可以输出到与聚合运行位置不同的数据库中的一个集合。
以下聚合操作对 books
集合中的数据进行透视,从而按作者对书名分组,然后将结果写入 reporting
数据库中的 authors
集合:
db.getSiblingDB("test").books.aggregate( [ { $group : { _id : "$author", books: { $push: "$title" } } }, { $out : { db: "reporting", coll: "authors" } } ] )
- 第一阶段 (
$group
): $group
阶段按authors
进行分组,并使用$push
将书名添加到books
数组字段:{ "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] } { "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } - 第二阶段(
$out
): $out
阶段将文档输出到reporting
数据库中的authors
集合。
要查看输出集合中的文档,运行以下操作:
db.getSiblingDB("reporting").authors.find()
该集合包含以下文档:
{ "_id" : "Homer", "books" : [ "The Odyssey", "Iliad" ] } { "_id" : "Dante", "books" : [ "The Banquet", "Divine Comedy", "Eclogues" ] }