MongoDB 视图

最后更新: 2021-07-25 21:42:07 +0800 +0800
原文以英文撰写。您正在阅读AI翻译版本。

MongoDB 视图是针对集合或其他视图的只读查询定义。视图存储的是聚合管道,而不是管道结果,因此每次读取都会将管道应用于当前源数据。标准视图不会提供物化视图缓存。

创建视图 #

db.createView() 接收目标集合名称、源命名空间和聚合管道:

javascript
db.createView(
  "active_orders",
  "orders",
  [
    { $match: { status: "active" } },
    { $project: { customerId: 1, total: 1, createdAt: 1 } }
  ]
)

客户端查询 active_orders 的方式与查询集合相同:

javascript
db.active_orders.find({ customerId: customerId })

服务器将视图定义与客户端查询结合起来,并针对源集合规划结果。标准视图使用其底层集合上的索引;不能直接在标准视图上创建、删除或重建通用索引。应将选择性 $match 阶段放在前面,并为管道和客户端查询使用的源字段建立索引。

也可以使用 db.createCollection() 创建视图:

javascript
db.createCollection("recent_orders", {
  viewOn: "orders",
  pipeline: [
    { $match: { createdAt: { $gte: ISODate("2026-01-01") } } }
  ],
  collation: { locale: "en", strength: 2 }
})

视图及其源必须位于同一数据库中。视图的默认排序规则在创建时固定,查询不能使用不同的排序规则覆盖它。

设计约束 #

视图可以公开字段子集、重命名字段、使用 $lookup 连接另一个集合,或聚合数据。它不能接受插入、更新或删除。包括 $out 和 $merge 在内的不受支持聚合阶段不能出现在标准视图定义中,因为它们会写入数据。

视图可以依赖其他视图,但依赖图不能包含循环。应保持管道具有确定性并且有界。每次请求都执行大型 $lookup、$group 或排序的管道,会将运行成本从写入转移到读取。

视图不支持时间点或快照读取隔离。阻塞型聚合阶段也受服务器聚合内存和临时文件行为的约束。应解释并对最终查询进行负载测试,而不是假设将管道隐藏在视图后就会降低成本。

授权和模式边界 #

启用身份验证时,创建视图需要数据库上的 createCollection 权限,以及对所引用命名空间的相关读取权限。查询视图需要对视图命名空间的 find 权限;客户端不需要同时拥有对源集合的直接 find 权限。

授权分离可以公开受控投影,例如不包含个人身份信息字段的员工记录。如果其他权限仍能公开源集合、元数据或旁信道,视图就不是完整的安全边界。只向应用程序账户授予所需的命名空间和命令。

标准视图没有独立的文档验证模式,因为它不能接受写入。源集合上的验证会限制对该集合的写入,但不能保证投影、$lookup 或计算字段永远符合应用程序模式。应将视图定义和消费者契约一起进行版本控制。视图及其引用的每个命名空间必须位于同一数据库中;视图不能跨越数据库命名空间边界。

标准视图和按需物化视图 #

当新鲜度重要且底层查询成本低时,标准视图很合适。当派生结果成本高但可以容忍刷新延迟时,MongoDB 将通过聚合管道填充的集合称为按需物化视图:

javascript
db.orders.aggregate([
  { $group: { _id: "$customerId", lifetimeValue: { $sum: "$total" } } },
  { $merge: { into: "customer_lifetime_value", whenMatched: "replace",
              whenNotMatched: "insert" } }
])

目标是一个真实集合,因此可以建立索引并高效查询。$merge 可以增量替换匹配文档,而 $out 会替换目标集合。调度器、变更流消费者、Atlas Stream Processing 管道或应用程序工作流必须刷新结果。应明确说明新鲜度契约,因为普通聚合不会持续维护按需物化视图。

当 $merge 作业更新许多文档时,读取者可能观察到部分刷新的目标。如果消费者需要单版本可见性,应写入带版本号的集合,在验证后切换一个小型元数据指针,然后回收旧版本。运行流程中要考虑重复存储、索引构建、刷新期间的变更捕获和清理失败。

当消费者需要通过变更流观察目标时,使用 $merge。通过 $out 替换的集合不能作为同一物化视图更新机制被监视。

参考资料 #

评论

在 GitHub 上阅读或评论(发表评论需要登录)