MongoDB 是最流行的文档数据库,但「能存 JSON 的数据库」这个理解会误导选型。本文讲清文档模型与关系模型的本质差异、BSON 的取舍、MongoDB 该用与不该用的边界。

文档模型 vs 关系模型:差异不在语法,在聚合边界

关系模型把业务对象拆散到多张表里:一个订单对象拆成订单行、订单明细行、收货地址行,靠 JOIN 在查询时拼回去。文档模型反过来,把一个业务对象完整存成一条文档:

{
_id: ObjectId("..."),
orderNo: "A20260101",
buyer: { userId: 123, name: "张三" },
items: [ { sku: "S1", qty: 2 }, { sku: "S2", qty: 1 } ],
address: { city: "杭州", detail: "..." },
status: "PAID"
}

术语对照很简单:表→集合,行→文档,列→字段。真正的差异在聚合边界:文档模型默认「一次读取取回一个完整业务对象」,单文档读写天然原子,不需要 JOIN;关系模型默认「实体归一化存放」,靠 JOIN 保证任意组合查询的灵活性。前者的软肋是跨集合关联——MongoDB 没有真正的 JOIN,$lookup 只是聚合管道里成本不低的补丁。

BSON:为效率付一点空间税

文档在磁盘和内存里的形态是 BSON(Binary JSON)。相比 JSON 文本,它做了三件事:扩充类型系统(ObjectId、Date、64 位整数、Decimal128、二进制等);给每个元素加长度前缀,解析器可以跳过无关字段直接定位;二进制编码省去文本解析开销。代价是同样的数据 BSON 通常比 JSON 略占空间,单文档还有 16MB 上限——这是用空间换扫描效率的明确取舍。

建模的两个基本决策

文档模型的核心问题是内嵌还是引用:一起读写的数据内嵌进同一文档(订单与明细),独立演进或被多处复用的数据用 ID 引用(订单与用户)。其次是控制数组规模——评论、操作记录这类无限增长的数组要拆成独立集合,否则文档会撞上 16MB 上限并让更新越来越重。「schema 灵活」指的是写入前不用 DDL,不代表可以不设计;生产上通常配合 schema validation 约束字段,避免结构漂移。

什么时候选 MongoDB

适合的信号很明显:

  • schema 演进快:内容、商品、表单类业务,字段随需求频繁增减,关系库加列改表痛苦,文档模型直接写新结构。
  • 日志与事件流:写入量大、结构松散、按时间衰减,配合 TTL 索引自动过期。
  • 内容管理与用户画像:嵌套结构内聚,一次查询取回完整对象。
  • 需要水平扩展:数据量超单机容量时,原生分片比关系库的分库分表中间件顺滑。

不该用的信号同样明显:

  • 强跨实体事务:转账、账务这类必须多实体强一致的场景,MongoDB 虽在 4.0/4.2 后支持副本集与分片上的多文档事务,但性能代价大、限制多,主力交易链路仍应放关系库。
  • 复杂关联与即席分析:大量 JOIN、自由组合的多维报表,是关系模型与 OLAP 引擎的主场。

副本集与分片:一句话定位

副本集解决高可用:一主多从加选举,主宕机自动切换;分片解决扩展性:按分片键把数据水平切到多个分片,每个分片自己还是副本集。前者管「宕机不死」,后者管「数据装不下、写入扛不住」,二者正交组合。

继续深入