$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
coll
输出集合名称。
timeseries
这是一个文档,用于指定写入到时间序列集合时使用的配置。
timeField
是必需的。所有其他字段是可选的。timeField
写入到时间序列集合时是必需的。.. include:: /includes/time-series/fact-time-field-description.rst
metaField
可选。包含每个时间序列文档中元数据的字段的名称。指定字段中的元数据应是用于标记一系列独一无二的文档的数据。元数据应该很少改变(如有)。指定字段的名称可能不是
timeseries.timeField
或与_id
相同。该字段可以是任何数据类型。虽然
metaField
字段是可选的,但使用元数据可以改进查询优化。 例如,MongoDB 会自动为新集合的metaField
和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
操作不会对预先存在的集合进行任何更改。
模式验证错误
如果您的 coll
集合使用模式验证且将 validationAction
设置为 error
,则插入带有 $out
的无效文档会引发错误。$out
操作不会对预先存在的集合进行任何更改,并且聚合管道返回的文档不会添加到 coll
集合中。
索引约束
如果管道生成的文档违反任何唯一索引(包括针对原始输出集合的 _id
字段的索引),则管道无法完成。
如果 $out
操作修改具有 Atlas Search索引的集合,您必须删除并重新创建搜索索引。请考虑改用 $merge
。
majority
读关注 (read concern)
您可以为包含 $out
阶段的聚合指定读关注级别 "majority"
。
互动 mongodump
如果客户端在转储过程中发出包含 $out
的聚合管道,则使用 --oplog
启动的mongodump
会失败。有关更多信息,请参阅 mongodump --oplog
。
限制
限制 | 说明 |
---|---|
聚合管道不能在事务中使用 $out 。 | |
在 7.0.3 之前的 MongoDB 版本中,聚合管道无法使用 $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" ] }