MongoDBNotes

第 01 章:认识 MongoDB

zjc 于 2026-01-01 发布

这是《MongoDB 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 MongoDB 是面向文档的分布式数据库。它用 BSON 文档保存数据,用集合组织文档,用丰富的索引和聚合管道提供查询分析能力,并通过副本集和分片提供高可用与横向扩展。

MongoDB 不是“比 MySQL 更随意的数据库”。好的 MongoDB 设计仍然需要明确实体边界、访问模式、一致性要求、索引策略和分片键。

1.1 为什么需要文档数据库

一个商品有多组属性:

{
  "sku_id": "sku_10001",
  "title": "轻薄笔记本",
  "price": 5999,
  "attrs": [
    { "name": "CPU", "value": "16核" },
    { "name": "内存", "value": "32GB" }
  ],
  "images": ["a.jpg", "b.jpg"],
  "tags": ["轻薄", "高续航"]
}

如果用关系表建模,会拆成商品表、属性表、图片表和标签表。对于强事务、强约束的数据,这很合理;但对于读多写少、结构变化快、整体读取的文档,拆表会增加复杂度。

MongoDB 的优势:

  1. 文档结构贴近业务对象;
  2. 数组和嵌套对象可自然表达;
  3. Schema 更灵活,支持字段演进;
  4. 单文档 ACID 事务;
  5. 聚合管道表达能力强;
  6. 原生支持水平分片;
  7. JSON 开发体验友好。

1.2 MongoDB 的核心概念

关系型术语 MongoDB 术语 说明
Database Database 数据库
Table Collection 集合
Row Document 文档
Column Field 字段
Primary Key _id 文档唯一标识
Join $lookup / Embedded 关联或内嵌
Index Index 索引

一个文档示例:

db.products.insertOne({
  sku_id: "sku_10001",
  title: "轻薄笔记本",
  price: NumberDecimal("5999.00"),
  attrs: [
    { name: "CPU", value: "16核" },
    { name: "内存", value: "32GB" }
  ],
  status: "ON_SALE",
  created_at: new Date()
});

1.3 BSON 与 JSON

MongoDB 在网络上常用 JSON,在存储层使用 BSON。

BSON 是二进制 JSON,支持:

{
  _id: ObjectId("66cb0c7f9e2a1f2b3c4d5e6f"),
  price: NumberDecimal("19.90"),
  created_at: ISODate("2026-08-25T10:00:00Z"),
  binary_field: BinData(0, "aGVsbG8=")
}

金额不要直接用 double,应使用 NumberDecimal

1.4 嵌套与引用

文档建模的核心选择:

方式 特点 适合
内嵌 Embedded 一次读取完整对象 一对少、整体读取
引用 Reference 分开存储再关联 一对多、多对多、大对象
混合 常用部分内嵌,历史部分引用 复杂业务

内嵌示例

{
  user_id: "u_1001",
  name: "Alice",
  addresses: [
    { type: "home", city: "Shanghai" },
    { type: "work", city: "Beijing" }
  ]
}

适合:地址数量有限,查询用户时通常一起返回。

引用示例

// users
{ _id: "u_1001", name: "Alice" }

// orders
{
  order_id: "o_10001",
  user_id: "u_1001",
  amount: NumberDecimal("199.00")
}

适合:订单数量无限增长,不能全部内嵌到用户文档。

建模原则:

  1. 按查询建模,而不是按实体关系机械翻译;
  2. 避免无界数组;
  3. 大字段和低频字段考虑拆分;
  4. 高频更新的计数不要放在大文档里;
  5. 单文档大小上限通常按 16MB 设计,但生产应远小于该值。

1.5 MongoDB 架构概览

单机 MongoDB 由 mongod 进程提供服务,生产环境通常使用副本集。

Replica Set
  |-- Primary       接收写入
  |-- Secondary 1   同步数据,可提供读
  |-- Secondary 2   同步数据,提高可用性
  +-- Arbiter       可选,只参与投票不存数据

当 Primary 不可用时,具备投票权的节点会选出新 Primary。

分片集群

Client
  -> mongos Router
     -> Shard 1 Replica Set
     -> Shard 2 Replica Set
     -> Shard 3 Replica Set
Config Server
组件 职责
mongos 路由请求,不存业务数据
Shard 存储数据分片
Config Server 保存集群元数据和 chunk 信息
Shard Key 决定数据分布

1.6 读写关注

MongoDB 提供可调的一致性语义。

Write Concern

db.orders.insertOne(
  { order_id: "o_10001", amount: 100 },
  { writeConcern: { w: "majority", wtimeout: 3000 } }
);
级别 含义
w: 1 Primary 确认
w: majority 多数节点确认
j: true 落 journal

关键交易数据建议使用 majority 写关注。

Read Concern

控制读取的数据一致性级别,常见包括 local、majority、linearizable。

Read Preference

控制读请求路由:

模式 说明
primary 只读 Primary
primaryPreferred 优先 Primary
secondary 只读 Secondary
secondaryPreferred 优先 Secondary
nearest 最低延迟节点

Secondary 读可能带来复制延迟,需要结合业务容忍度。

1.7 MongoDB 与 MySQL 的边界

维度 MongoDB MySQL
数据模型 文档 关系表
Schema 灵活 强约束
事务 多文档事务可用但成本高 强项
关联 内嵌或 $lookup JOIN
扩展 原生分片成熟 常依赖中间件或架构拆分
金额与强一致 可用但需谨慎 更常用
迭代速度 字段演进快 DDL 成本更高

适合 MongoDB:

更适合 MySQL:

1.8 生产使用红线

  1. 生产必须副本集部署,不能单点;
  2. 分片键必须提前设计,事后改造成本高;
  3. 每个查询都要有索引支撑;
  4. 避免无界数组无限增长;
  5. 金额使用 Decimal128;
  6. 多文档事务要短小;
  7. Secondary 读必须监控复制延迟;
  8. 必须启用认证、网络隔离和 TLS;
  9. 备份必须可恢复并定期演练;
  10. 慢查询和锁等待要有监控。

本章小结

MongoDB 以文档模型、灵活 Schema、聚合管道、副本集和分片见长。它的设计重点是“按访问模式建模”:确定读取形态,再决定内嵌或引用;确定一致性要求,再选择读写关注;确定规模和热点,再设计分片键。它不是关系型数据库的替代品,而是业务模型适配的另一种选择。

思考题

  1. 什么数据适合内嵌,什么数据适合引用?
  2. MongoDB 的副本集和分片分别解决什么问题?
  3. 为什么无界数组是危险设计?
  4. Secondary 读会带来什么一致性风险?
  5. 如果让你把商品详情从 MySQL 迁到 MongoDB,如何设计文档结构?