Docs 菜单
Docs 主页
/
MongoDB Manual
/ / /

$out(聚合)

在此页面上

  • 定义
  • 语法
  • 行为
  • 示例
$out

获取聚合管道返回的文档并将其写入指定集合。您可以指定输出数据库。

$out阶段必须是管道中的最后一个阶段$out操作符允许聚合框架返回任意大小的结果集。

警告

$out将替换指定的集合(如果存在)。 有关详细信息,请参阅替换现有集合

$out 阶段采用以下语法:

  • $out 可以使用文档来指定输出数据库以及输出集合:

    { $out: { db: "<output-db>", coll: "<output-collection>" } }
    字段
    说明

    输出数据库名称。

    • 对于副本集或独立运行副本集,如果输出数据库不存在, $out也会创建该数据库。

    • 对于分片集群,指定的输出数据库必须已经存在。

    输出集合名称。

  • $out 可以采用字符串来仅指定输出集合(即输出到同一数据库中的集合):

    { $out: "<output-collection>" } // Output collection is in the same database

重要

  • 您不能将分片集合指定为输出集合。管道的输入集合可以进行分片。要输出到分片集合,请参阅 $merge (从 MongoDB 4.2 开始提供)。

  • $out操作符无法将结果写入固定大小集合。

  • 如果修改带 Atlas Search 索引的集合,必须先删除搜索索引,然后重新创建搜索索引。请考虑改用 $merge

随着版本4.2中引入$merge , MongoDB 提供了两个阶段$merge$out ,用于将聚合管道的结果写入集合。 这两个阶段的功能总结如下:

  • 可以输出到相同或不同数据库中的集合。

  • 可以输出到相同或不同数据库中的集合。

  • 如果输出集合不存在,则创建一个新集合。

  • 如果输出集合不存在,则创建一个新集合。

  • 完全替换已存在的输出集合。

  • 可将结果(插入新文档、合并文档、替换文档、保留现有文档、操作失败、使用自定义更新管道处理文档)并入现有集合。

    可以替换集合的内容,但前提是聚合结果包含集合中所有现有文档的匹配项。

  • 无法输出到分片集合。但是,可以对输入集合进行分片。

  • 可输出到分片集合。输入集合也可以是分片的。

  • 对应 SQL 语句:

    • INSERT INTO T2 SELECT * FROM T1
    • SELECT * INTO T2 FROM T1
  • 对应 SQL 语句:

    • MERGE T2 AS TARGET
      USING (SELECT * FROM T1) AS SOURCE
      ON MATCH (T2.ID = SOURCE.ID)
      WHEN MATCHED THEN
      UPDATE SET TARGET.FIELDX = SOURCE.FIELDY
      WHEN NOT MATCHED THEN
      INSERT (FIELDX)
      VALUES (SOURCE.FIELDY)
    • 创建/刷新物化视图

从 MongoDB5.0 开始,如果集群中的所有节点都将$out featureCompatibilityVersion 5.0设置为 或更高版本,并且“ 读取偏好” 设置为从节点,则 可以在副本集从节点上运行。

$out语句的读取操作发生在从节点上,而写入操作仅发生在主节点上。

并非所有驱动程序版本都支持将$out操作定位到副本集从节点。 检查驱动程序文档,了解驱动程序何时添加了对在从节点上运行的$out的支持。

如果集合尚不存在,则$out操作会创建一个新集合。

在聚合完成之前,集合不可见。如果聚合失败,则 MongoDB 不会创建集合。

如果$out操作指定的集合已经存在,则在聚合完成后, $out阶段将以原子方式将现有集合替换为新的结果集合。 具体来说, $out操作:

  1. 创建临时集合。

  2. 将现有集合中的索引拷贝到临时集合。

  3. 将文档插入临时集合。

  4. 使用 dropTarget: true 调用 renameCollection 命令,将 temp 集合重命名为目标集合。

$out操作不会更改上一个集合中存在的任何索引。 如果聚合失败,则$out操作不会对预先存在的集合进行更改。

如果您的 coll 集合使用模式验证且将 validationAction 设置为 error ,则插入带有 $out 的无效文档会引发错误。$out 操作不会对预先存在的集合进行任何更改,并且聚合管道返回的文档不会添加到 coll 集合中。

如果管道生成的文档违反任何唯一索引(包括针对原始输出集合的 _id 字段的索引),则管道无法完成。

如果$out操作修改了具有Atlas Search索引的集合,则必须删除并重新创建Atlas Search索引。 请考虑改用$merge

您可以为包含 $out 阶段的聚合指定读关注级别 "majority"

mongodump--oplog如果客户端在转储进程中发出包含 的聚合管道,则使用$out 将失败。有关更多信息,请参阅mongodump --oplog

限制
说明
聚合管道不能在事务中使用 $out
聚合管道不能使用 $out 输出到时间序列集合。
不允许将$out阶段作为视图定义的一部分。 如果视图定义包含嵌套管道(例如视图定义包含$lookup$facet阶段),则此$out阶段限制也适用于嵌套管道。
$lookup 阶段
$facet 阶段
$facet 阶段的 嵌套管道不能包括 $out 阶段。
$unionWith 阶段
$unionWith 阶段的 嵌套管道不能包括 $out 阶段。
"linearizable" 读关注 (read concern)

$out 阶段不能与读关注 "linearizable" 一起使用。如果为 db.collection.aggregate() 指定 "linearizable" 读关注,则不能将 $out 阶段包括在管道中。

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 也会创建该数据库。

对于分片集群,指定的输出数据库必须已经存在。

$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" ] }

后退

$merge