MongoDB不支持自动定时刷新物化视图,需手动或外部调度触发$ out或$merge聚合管道;$out全量覆盖目标集合,$merge支持增量更新并可建索引和change stream。

MongoDB 本身不支持自动定时刷新物化视图,离线报表必须靠手动或外部调度触发更新。所谓“按需”,就是你决定什么时候跑一次 $out 或 $merge 聚合管道 —— 它不会自己在后台轮询、也不会监听数据变更后自动重算。
用 $out 创建一次性快照式物化视图
适合报表周期明确(比如每天凌晨跑一次)、且能接受视图内容完全覆盖的场景。
-
$out会**清空目标集合再写入**新结果,相当于全量重刷,语义简单但风险高:如果管道执行失败,目标集合就变空了 - 目标集合名必须是字符串字面量,不能带变量或表达式,例如:
{ $out: "daily_sales_summary" } - 无法对目标集合启用 change stream 监听 —— 因为每次写入都是全新替换,没有“文档级变更”可捕获
- 聚合管道里不能包含
$facet或$lookup(带 pipeline 的那种)等限制性阶段,否则$out会报错
用 $merge 实现增量/条件式更新
更适合需要保留历史中间状态、或只更新变动部分的离线报表逻辑。
-
$merge支持whenMatched: "replace"、"keepExisting"、"merge"等策略,可避免全量覆盖风险 - 必须指定
on字段(如{ on: "_id" }),MongoDB 会据此做 upsert;若字段无索引,性能会急剧下降 - 目标集合上可以创建普通索引,也能开启 change stream —— 这是
$out做不到的关键区别 - 注意:如果源数据中存在重复
on字段值,$merge会报错,得先确保去重或改用$out
没有内置调度器,得自己搭触发机制
Atlas UI 界面点一下就能跑,但生产环境不可能人工点。真实落地时得靠外部工具驱动:
- 用
mongosh+ cron(Linux)或 Task Scheduler(Windows)定期执行脚本,调用db.runCommand({ aggregate: ... }) - 用 Node.js / Python 写轻量服务,通过 MongoDB Driver 提交聚合命令,配合
node-schedule或APScheduler - 集成到 Airflow、Prefect 等编排平台,把物化视图更新作为 DAG 中的一个 task,便于监控和重试
- 别依赖 Atlas 的 “Scheduled Triggers” —— 它只支持监听集合变更,不能定时跑任意聚合,和物化视图更新无关
最容易被忽略的一点:物化视图的目标集合不是“视图”,而是真集合,它不继承原集合的索引,所有查询性能依赖你手动在目标集合上建的索引。漏建索引时,报表查询可能比直接查原始集合还慢。











