不,MongoDB 并不意味着跳过设计

发布: (2025年12月13日 GMT+8 07:07)
8 min read
原文: Dev.to

Source: Dev.to

领域驱动设计与 MongoDB

使用 MongoDB 时,领域驱动设计(DDD)帮助开发者通过让数据模型与业务逻辑和访问模式保持一致来构建稳健的系统。

开发者常常被不公平地指责为忽视数据完整性,因为文档数据库缺乏 SQL 数据库那种严格的结构。这种误解导致一些 DBA 认为只有关系型数据库才能保证数据质量,而使用 MongoDB 就意味着数据建模会出错。

实际上,开发者对数据完整性的关注程度与 DBA 并无二致。他们在应用的领域模型上投入大量精力,并且避免通过映射到一个不反映实际使用场景的规范化结构而削弱模型。

在文档数据库中,你仍然需要设计数据模型;不同之处在于设计发生的地点和方式——直接在领域模型和应用的访问模式旁边进行。对于实践 DDD 的团队来说,这一点尤为重要,因为开发者会花时间去理解领域对象、关系以及使用模式。

数据模型会随开发过程演进:头脑风暴、原型设计、发布最小可行产品(MVP)以获取早期反馈,然后迭代至稳定、可投入生产的应用。

关系建模 vs 文档建模

关系建模 通常从一个在应用尚未完全理解之前就创建的规范化设计开始。随后该模型必须服务于多种未来工作负载和不可预测的数据分布。例如,为学术软件设计的模式可能会被小学和大型大学共同使用。这说明了关系型数据库的优势:即使工作负载差异巨大,暴露给应用的逻辑模型仍保持不变。

文档建模 则针对特定的应用使用情况进行定制。它不再把领域模型转换为规范化表——这种做法会增加抽象层并隐藏性能优化——而是让 MongoDB 直接存储代码和业务逻辑中出现的聚合。文档反映业务事务,并以连续块的形式写入磁盘,使物理模型与领域模式保持一致并针对访问模式进行优化。

关键对比

  • 关系

    • 在关系型数据库中,“关系”指的是数学意义上的元组集合,而不是它们之间的连接。规范化实际上松散了关系,在查询时通过连接将实体重新组合。
    • 实体‑关系图(ERD)展示的是通过主键和外键实现的一对一或一对多的简单链接,但它们并未捕获导航方向或所有权。多对多关系通过关联表建模,进而被拆分为两个一对多关系。
  • UML vs ERD

    • UML 类图提供了更丰富的语义:导航方向、关联、聚合、组合以及继承。
    • 在 MongoDB 中,这些概念可以自然映射:
      • 组合(例如订单及其订单行)通常表现为嵌入式文档,共享生命周期,防止部分删除。
      • 聚合(例如客户及其订单)在生命周期不同或所有权共享时使用引用。
      • 继承 可以通过多态实现,避免在 ERD 中需要的可空列等变通做法。
  • 模式刚性

    • 关系模式对实体是刚性的;关系在运行时通过连接解析,类似数据科学家在分析过程中发现相关性。
    • MongoDB 的模式灵活性让领域模型与存储表示保持紧密对齐。

MongoDB 中的模式灵活性

MongoDB 是模式灵活的,而非无模式。这对早期项目——头脑风暴、原型开发或构建 MVP——非常有价值,因为你不必在写入数据前执行数据定义语言(DDL)语句。模式存在于应用代码中,文档原样存储,最初没有验证。

随着模型成熟,你可以直接在数据库中定义模式验证规则(字段必需、数据类型、取值范围等)。不需要一次性声明所有字段;验证可以逐步添加,以确保在多个组件依赖相同字段或创建索引时结构保持一致。

模式灵活性的好处

  • 快速原型:自由添加字段,无需担心即时验证。
  • 受控演进:随后启用验证,让数据库负责数据完整性,减少重复的应用层检查。
  • 物理约束执行:例如,你可以验证嵌入的订单项数组不超过某个大小。MongoDB 可以记录警告而不是直接失败,从而在标记潜在异常的同时保持应用可用。

参照完整性与关系

在 SQL 数据库中,外键是一种约束,用于防止异常(孤儿行、级联删除),但它们并不在 JOIN 子句中使用;关系在查询时定义。

MongoDB 采用不同的方式:

  • 嵌入 紧密耦合的实体(例如订单文档内的订单行)从设计上就消除了孤立项。
  • 引用 由应用逻辑处理,通常在嵌入值之前先从稳定的集合中读取。

因为 MongoDB 模型是为已知的访问模式和生命周期构建的,参照完整性通过业务规则而非通用约束来维护。这与现实世界的流程相吻合——更新或删除必须遵循特定条件(例如,降价可能适用于进行中的订单,而涨价则可能不适用)。

Back to Blog

相关文章

阅读更多 »