首页/数据/NoSQL 速查/变更流 change stream 监听
MongoDB99 条

变更流 change stream 监听

watch() 基于 oplog 输出数据变更事件(插入/更新/删除),支持断点续传(resume token),适合做数据同步与事件驱动。

NoSQL 速查数据更新于 2026-10-13

变更流能做什么

watch() 让应用订阅数据变更:集合级、库级或整个实例级都可以监听,事件里带操作类型、文档主键与完整文档(可选)。它基于 oplog 实现,因此天然有序、支持断点续传——把 resume token 存下来,重启后接着上次位置继续消费。这正是搜索索引同步、缓存失效与事件驱动链路常用的基础设施。

基本信息

前提复制集或分片集群(单节点非复制集不支持)
语法db.coll.watch(pipeline, options),也可 watch 整个库或实例
事件字段operationType、documentKey、fullDocument、updateDescription、clusterTime
断点续传resumeAfter、startAfter 或 startAtOperationTime 指定起始位置
完整文档fullDocument: "updateLookup" 可取当前已提交版本
权限要求需要集合或库级别的变更流读取权限

典型使用场景

  • 搜索索引同步:把变更投递给索引更新链路,替代定时全量扫描
  • 缓存失效:文档更新后主动清理或刷新对应缓存键
  • 事件驱动:订单状态变化触发通知、风控与下游流程
  • 审计与留痕:把变更事件写入专用集合供追溯
  • 数据迁移过渡期:新旧结构并存时同步写入两套存储

mongosh 示例

mongosh 示例
// 只关注插入事件,并只输出必要字段
const cs = db.orders.watch([
  { $match: { operationType: { $in: ["insert", "update"] } } },
  { $project: { "documentKey._id": 1, operationType: 1, fullDocument: 1, updateDescription: 1 } }
])

cs.on("change", (ev) => {
  printjson({ key: ev.documentKey, op: ev.operationType, doc: ev.fullDocument, token: ev._id })
})

// 应用侧持久化 ev._id 作为 resume token:重启后用 resumeAfter 续传
// 更新事件默认不带完整文档,需要时在 watch 选项里指定 fullDocument 读取当前版本

事件字段读法

字段含义使用要点
operationTypeinsert / update / replace / delete / invalidate 等invalidate 表示事件已失效,需要重新建立监听
documentKey被操作文档的主键作为幂等去重与目标定位的依据
fullDocument操作后的完整文档更新事件默认不返回,需显式指定读取方式
updateDescription更新的字段与删除的字段清单用于只同步变化部分,减少写入量
clusterTime集群时间戳可作为顺序参考与调试依据
_id(事件 id)resume token必须持久化保存才能断点续传
变更流受 oplog 保留窗口约束:消费者长时间断开后如果起始位置已被截断,就只能改从当前时间重新开始,因此 token 与消费延迟都要监控。
变更事件是至少一次投递:消费端必须幂等,重复收到同一事件时不能重复产生副作用。

易错点

  • 在单节点(非复制集)上使用变更流:功能直接不可用,本地验证需先起单节点复制集
  • resume token 只放在内存里:进程重启后无法续传,只能从当前位点开始并丢失中间变更
  • 消费端不做幂等:重复事件导致重复写索引或重复发通知,下游出现脏数据
  • 消费延迟长期高于 oplog 窗口:位点被截断后订阅失效,同步链路出现不可自愈的缺口

数据来源与参考

  • MongoDB Manual: Change Streams
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌