Docs 主页 → 开发应用程序 → MongoDB Manual
$out(聚合)
定义
$out
获取聚合管道返回的文档并将其写入指定的collection。您可以指定输出数据库。
$out
阶段必须是管道中的最后一个阶段。$out
操作符允许聚合框架返回任意大小的结果集。警告
如果
$out
操作指定的集合已经存在,则$out
阶段会在聚合完成后以原子方式将现有集合替换为新的结果集合。有关详细信息,请参阅替换现有集合。
语法
$out
阶段使用以下语法:
$out
可以采用字符串来仅指定输出集合(即输出到同一数据库中的集合):{ $out: "<output-collection>" } // Output collection is in the same database $out
可以使用文档来指定输出数据库以及输出collection:{ $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" , } } } 重要
更改时间序列粒度
在创建时间序列集合后,您可以使用
collMod
方法修改其粒度。不过,您只能增加每个存储桶涵盖的时间跨度,而不能减少该时间跨度。字段说明db
coll
输出集合名称。
timeseries
这是一个文档,用于指定写入到时间序列集合时使用的配置。
timeField
是必需的。所有其他字段是可选的。timeField
写入到时间序列集合时是必需的。.. include:: /includes/time-series/fact-time-field-description.rst
metaField
可选。包含每个时间序列文档中元数据的字段的名称。指定字段中的元数据应用于标识一系列唯一文档的数据。元数据应该很少改变(如果有的话)。
指定字段的名称不能是
_id
,也不能与timeseries.timeField
相同。字段可以是任何类型。granularity
可选。如果设置
bucketRoundingSeconds
和bucketMaxSpanSeconds
,请勿使用。可能的值为
seconds
(默认)、minutes
、和hours
。将
granularity
设置为最接近连续输入时间戳之间时间的值。这可通过优化 MongoDB 在集合中存储数据的方式来提高性能。有关粒度和桶间隔的更多信息,请参阅设置时间序列数据的粒度。
bucketMaxSpanSeconds
可选。与
bucketRoundingSeconds
结合使用以作为granularity
的替代方案。设置同一存储桶中不同时间戳之间的最大时间间隔。可能的值为 1-31536000。
6.3 版本中的新功能。
bucketRoundingSeconds
可选。与
bucketMaxSpanSeconds
结合使用作为granularity
的替代方案。必须等于bucketMaxSpanSeconds
。当文档需要新的存储桶时,MongoDB 会按此间隔对文档时间戳的值向下取整,以设置存储桶的最小开始时间。
6.3 版本中的新功能。
重要
您不能将分片集合指定为输出集合。可以对管道的输入集合进行分片。要输出到分片集合,请参阅
$merge
。$out
操作符无法将结果写入到固定大小集合。如果修改具有Atlas Search索引的集合,则必须先删除搜索索引,然后重新创建。请考虑改用
$merge
。
使用以下项进行比较 $merge
MongoDB 提供了两个阶段($merge
和 $out
),以将聚合管道结果写入到集合中。下面简要介绍了这两个阶段的功能:
$out | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
| ||||||||||
|
|
行为
$out 读取操作在从节点副本集成员上运行
从 MongoDB 5.0 开始,如果集群中的所有节点将 featureCompatibilityVersion 设置为 5.0
或更高版本并将读取偏好设置为从节点,则 $out
可以在副本集从节点上运行。
$out
语句的读取操作在从节点上执行,而写入操作仅在主节点上执行。
并非所有驱动程序版本都支持将$out
操作定位到副本集从节点。检查驱动程序文档,了解驱动程序何时添加了对在从节点上运行的$out
的支持。
创建新集合
如果集合还不存在,$out
操作将创建一个新集合。
在聚合完成之前,集合不可见。如果聚合失败,则 MongoDB 不会创建集合。
替换现有集合
如果 $out
操作指定的集合已存在,在聚合完成后,$out
阶段自动将现有集合替换为新的结果集合。具体来说,$out
操作:
创建临时集合。
将现有集合中的索引拷贝到临时集合。
将文档插入临时集合。
使用
dropTarget: true
调用renameCollection
命令,将 temp 集合重命名为目标集合。
如果指定的集合存在,并且 $out
操作指定 timeseries
选项,则以下限制适用:
现有集合必须是时间序列集合。
现有集合不能是视图。
$out
阶段中包含的timeseries
选项必须与现有集合上的选项完全匹配。
$out
操作不更改以前的集合上存在的任何索引。如果聚合失败,$out
操作不会对预先存在的集合进行任何更改。
索引约束
如果管道生成的文档违反任何唯一索引(包括针对原始输出集合的 _id
字段的索引),则管道无法完成。
如果$out
操作修改具有Atlas Search索引的集合,则必须删除并重新创建搜索索引。请考虑改用$merge
。
majority
读关注 (read concern)
从 MongoDB4 开始。2 ,您可以为包含 阶段的聚合指定"majority"
读关注$out
级别 。
互动 mongodump
mongodump
--oplog
如果客户端在转储进程中发出包含 的聚合管道,则使用$out
将失败。有关更多信息,请参阅mongodump --oplog
。
限制
限制 | 说明 |
---|---|
聚合管道不能在事务中使用 $out 。 | |
在7之前的 MongoDB 版本中。 0 。 3 ,聚合管道无法使用 $out 输出到时间序列集合。 | |
$lookup 阶段 | |
$facet 阶段 | |
$unionWith 阶段 | $unionWith 阶段的嵌套管道不能包含 $out 阶段。 |
"linearizable" 读关注 (read concern) | 从 MongoDB4 开始。2 时, |
举例
在 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
可以输出到与运行聚合的数据库不同的collection中的数据库。
以下聚合操作对 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" ] }