引言

子文档以及引用类型是MongoDB中两种常见的数据建模方式,它们分别适用于不同的业务需求和使用场景,下面从定义、优缺点、适用场景、操作对比等方面分析它们的区别

嵌套文档模式(Subdocument)

  • 定义:将关联数据嵌套在主文档内,所有的相关的信息都被存储在统一个文档之中;
  • 优点:读取性能快、操作简单;
  • 缺点:数据冗余,文档可能会变得过大;
  • 适用场景:
    • 存储具有强关联性的数据,比如一个订单以及其订单项、一个博客文章以及其评论、一个用户以及其地址列表;
    • 需要高效地一次性读取所有数据,比如博客文章以及其评论;
    • 数据量较小且关系稳定、结构清晰的嵌套数据,比如用户以及其地址;
    • 需要事务性操作(需要确保其原子性),比如订单支付状态和日志;
    • 层级嵌套的数据结构,比如分类树、组织架构等;
  • 不适用场景:
    • 数据规模可能无限增长,导致容易超过MongoDB16MB的限制,像是系统的操作日志;
    • 需要单独查询子文档,如果子文档中的数据经常需要单独查询,采用文档嵌套的方式将会导致查询效率低,比如商品和评论;
    • 需要频繁更新子文档,整个文档的更新开销会较大;
    • 数据查询复杂,需要跨多个文档关联查询等操作,比如订单、商品、用户

引用文档模式(Ref)

  • 定义:关联数据存储在不同的集合中,通过引用(如_id)建立起关联关系;
  • 优点:文档小且可服用,支持更大的数据集合;
  • 缺点:查询时,需要额外的join操作(一般在应用层完成);
  • 适用场景:
    • 数据规模可能无限增常,比如用户的操作日志;
    • 需要单独查询子文档,比如商品和评论;
    • 需要频繁更新子文档,比如用户的好友列表;
    • 数据查询复杂,徐亚跨多个文档来进行操作,比如订单、用户、商品;
  • 不适用场景:

两种模式的对比分析

下面以一表格来对接一下两者

特性 子文档 引用类型
数据关系 强关联关系,逻辑上不可分离 弱关联,可独立存在
查询效率 一次性查询完整的数据 需要多次查询或者是需要$lookup操作
数据冗余 数据冗余可能会比较多 数据冗余少,去中心化设计
文档大小限制 MongoDB文档大小(16MB)限制 子集合独立存储,不受限制
扩展性 子文档数据量固定或者有限 子数据增长量不受影响
适用场景 强关联数据、小数据量、结构文档 弱关联数据、大数据量、跨集合查询

实际案例分析

下面以用户以及用户的收货地址管理为例子,来具体分析一下两者在使用上的不同,具体见下图所示:
嵌套文档与引用文档的使用对比

使用建议

  1. 优先使用子文档:在满足查询需求的前提下,有限考虑将数据存储在一个文档中;
  2. 避免嵌套过深:子文档嵌套层次过深可能导致增加操作的复杂度,因此建议限制在2~3层;
  3. 定期评估数据模型:随着业务需求变化,评估子文档是否仍然适用,必要时进行拆分;
  4. 可简单采用一句话概括:如果子数据量小、变动少、关联性比较强,则采用子文档,如果子数据量较大、频繁更新或者需要独立查询,则采用引用类型