$out会无条件全量覆盖目标集合,因其本质是创建临时集合后重命名替换,导致原集合数据、索引、TTL及分片配置全部丢失;它不支持事务、不能用于视图或$lookup子管道,且不可逆。
会,而且是无条件、不可逆的全量覆盖。这不是 bug,是 $out 的设计本质决定的 —— 它不写入原集合,而是用临时集合重命名替换,旧数据、索引、TTL、分片配置全部消失。
$out 不是“往目标集合里插入”,而是一次原子性重命名操作:
esi.tmp.agg_out.2)renameCollection,将临时集合直接重命名为目标集合名这个过程跳过了所有文档级判断:哪怕管道只改了一个字段,哪怕只新增 1 条记录,只要用了 $out,目标集合就等同于被删掉重建。你看到的“覆盖”,其实是 MongoDB 删除旧集合 + 创建新集合的原子封装。
如果你需要保留原有数据或做增量更新,$merge 是唯一替代方案,但它和 $out 有根本差异:
$out:必须放在管道末尾;不支持事务;不保留任何原集合元数据;输出目标不能是时间序列集合$merge:也必须是最后一个阶段;支持 whenMatched(如 "replace"、"keepExisting")和 whenNotMatched(如 "insert");可指定 on 字段做 upsert;但同样不支持事务内使用$lookup 的子管道简单说:$out 是“换表”,$merge 是“改表里的内容”。选哪个,取决于你要的是快照导出,还是持续同步。
不行,服务端硬性拒绝。错误信息固定为:CommandNotSupported: $out is not allowed in transactions。
这不是语法或驱动问题,而是因为 $out 触发的是集合级元数据变更(重命名、隐式创建),无法被事务快照机制回滚。连 $merge 也被一并禁用。
可行路径只有两阶段应用层协调:
$facet 或多次 $group),调用 .toArray() 拉取结果到内存collection.insertMany(docs, { session }) 或 updateMany 写入目标集合bulkWrite,部分操作可能绕过 session 控制即使你没在事务里用 $out,这些点也常导致意外失败:
$out 不支持输出到 time-series collectionmongodump --oplog 备份期间有 $out 正在运行 → 备份会失败,因 $out 修改了集合元数据,破坏 oplog 一致性$out 的管道 → 服务端拒绝创建视图,语法校验即失败最危险的盲区是:你以为只是“导出一次”,但没意识到它顺手把索引和 TTL 全删了 —— 下次查 db.coll.getIndexes() 才发现只剩 _id_,而应用已经开始报慢查询。