$out(聚合)
定义
$out
将聚合管道返回的文档写入指定的集合。您可以指定输出数据库。
$out
阶段必须是管道中的最后一个阶段。$out
运算符允许聚合框架返回任何大小的结果集。警告
如果
$out
操作指定的集合已存在,则在聚合完成后,$out
阶段会原子性地用新的结果集合替换现有集合。有关详细信息,请参阅替换现有集合
语法
输出阶段 $out
有以下语法
$out
可以接受一个字符串来指定仅输出集合(即输出到同一数据库中的集合){ $out: "<output-collection>" } // Output collection is in the same database $out
可以接受一个文档来指定输出数据库以及输出集合{ $out: { db: "<output-db>", coll: "<output-collection>" } } 从 MongoDB 7.0.3 和 7.1 开始,
$out
可以接受一个文档来输出到时间序列集合:{ $out: { db: "<output-db>", coll: "<output-collection>", timeseries: { timeField: "<field-name>", metaField: "<field-name>", granularity: "seconds" || "minutes" || "hours" , } } } 字段描述db
输出数据库名。
对于副本集或独立服务器,如果输出数据库不存在,
$out
也会创建数据库。
coll
输出集合名。
timeseries
一个文档,指定写入时间序列集合时使用的配置。必须提供
timeField
。其他所有字段都是可选的。timeField
写入时间序列集合时必须提供。.. include:: /includes/time-series/fact-time-field-description.rst
metaField
可选。包含每个时间序列文档元数据的字段的名称。在指定的字段中的元数据应该是用于标记唯一文档序列的数据。元数据很少或几乎不会改变。指定字段的名称不得为
_id
或与timeseries.timeField
相同。字段可以是任何数据类型。尽管
metaField
字段是可选的,但使用元数据可以提高查询优化。例如,MongoDB自动为新集合在metaField
和timeField
字段上创建组合索引。如果您不为此字段提供值,数据将仅基于时间进行桶划分。granularity
可选。如果设置了
bucketRoundingSeconds
和bucketMaxSpanSeconds
,则不要使用。可能的值是
seconds
(默认值)、minutes
和hours
。将
granularity
设置为与连续传入时间戳之间的时间最接近的值。这通过优化MongoDB在集合中存储数据的方式来提高性能。有关粒度和桶间隔的更多信息,请参阅为时间序列数据设置粒度。
bucketMaxSpanSeconds
可选。与
bucketRoundingSeconds
一起使用,作为粒度
的替代方案。设置同一桶中时间戳之间的最大时间间隔。可能值为1-31536000。
新特性版本6.3.
bucketRoundingSeconds
可选。与
bucketMaxSpanSeconds
一起使用,作为粒度
的替代方案。必须等于bucketMaxSpanSeconds
。当文档需要新的桶时,MongoDB将文档的时间戳值按此间隔向下舍入,以设置桶的最小时间。
新特性版本6.3.
重要
您不能指定分片集合作为输出集合。管道的输入集合可以是分片的。要将输出输出到分片集合,请参阅
$merge
。$out
运算符不能将结果写入固定集合。如果您修改了一个包含Atlas Search索引的集合,您必须首先删除并重新创建搜索索引。考虑使用
$merge
代替。
与$merge
的比较
MongoDB提供了两个阶段,$merge
和$out
,用于将聚合管道的结果写入集合。以下总结了这两个阶段的功能
$out | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
|
行为
$out 在辅助副本集成员上运行读操作
从MongoDB 5.0版本开始,如果集群中所有节点都将功能兼容性版本设置为5.0或更高,并且将读取偏好设置为辅助,则$out
可以在副本集的辅助节点上运行。
$out
语句的读操作在辅助节点上执行,而写操作仅在主节点上执行。
并非所有驱动程序版本都支持将$out
操作的目标设置为副本集的辅助节点。请查阅您的驱动程序文档,以了解您的驱动程序何时添加了对在辅助节点上运行$out
的支持。
创建新集合
如果不存在,$out
操作将创建一个新的集合。
集合在聚合完成之前不可见。如果聚合失败,MongoDB不会创建集合。
替换现有集合
如果由 $out
操作指定的集合已存在,则在聚合完成后,$out
阶段会原子性地用新的结果集合替换现有的集合。具体来说,$out
操作
创建一个临时集合。
将现有集合的索引复制到临时集合中。
将文档插入到临时集合中。
使用带有
dropTarget: true
的renameCollection
命令将临时集合重命名为目标集合。
如果指定的集合存在并且 $out
操作指定了 timeseries
选项,则有以下限制
现有集合必须是时间序列集合。
现有集合不能是视图。
$out
阶段中包含的timeseries
选项必须与现有集合上的选项完全匹配。
$out
操作不会更改前一个集合上存在的任何索引。如果聚合失败,则 $out
操作不会对现有的集合进行任何更改。
模式验证错误
如果您的 coll
集合使用模式验证并且 validationAction
设置为 error
,则使用 $out
插入无效文档会引发错误。 $out
操作不会对现有的集合进行任何更改,并且聚合管道返回的文档不会添加到 coll
集合中。
索引约束
如果管道产生的文档违反了任何唯一索引,包括原始输出集合中 _id
字段的索引,则管道将无法完成。
如果 $out
操作修改了带有 Atlas Search 索引的集合,您必须删除并重新创建搜索索引。请考虑使用 $merge
代替。
majority
读取关注度
您可以为包含 读取关注度 阶段的聚合指定 "majority"
级别。
与 mongodump
的交互
当客户端在导出过程中发出包含 $out
的聚合管道时,以 mongodump
开始并带有 --oplog
的命令将失败。有关更多信息,请参阅 mongodump --oplog
。
限制
限制 | 描述 |
---|---|
聚合管道不能在 事务 中使用 $out 。 | |
$lookup 阶段 | |
$facet 阶段 | |
$unionWith 阶段 | $unionWith 阶段的嵌套管道不能包含 $out 阶段。 |
"linearizable" 读取关注点 |
|
示例
在 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
集合中的数据旋转,按作者分组标题,然后将结果写入同一数据库中的 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
也会创建数据库。
$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" ] }