深访第一站先认识这位"主人"本身:它从哪来、把哪些赌注押进了设计、赢得了什么、又明说了不擅长什么。本节是全章的坐标系——4.2 起的所有机制细节,都是本节能力清单的展开。
阅读完本节,你应当能够:
MongoDB 的起点是一家名为 10gen 的公司的内部平台项目,创始团队曾在双击广告公司处理海量点击流数据,深知固定表结构在高频迭代业务里的摩擦。2009 年,他们把项目独立开源,取名 MongoDB(humongous 的戏称,意为"巨大")。早期版本以"无模式、易上手、JSON 全家桶"快速积累了开发者人气;随后几年补齐了长期欠账:3.0 重写存储引擎、3.2 引入文档级校验、4.0 支持复制集内多文档事务、4.8 补上分片事务、6.0 与 7.0 持续强化聚合与查询能力。回头看,MongoDB 的演化史就是一部"把 NoSQL 缺的课逐步补上,同时守住易用与灵活"的历史。
四个设计赌注决定了它的长相。赌文档自完备:一个业务实体聚成一个文档,读取一次命中——这换来读性能,也让建模能力(嵌入 vs 引用,见 4.2)成为核心竞争力。赌 BSON 的类型丰富:JSON 的二进制扩展版支持日期、二进制、精确数值等类型,比纯 JSON 更贴近真实业务。赌默认易用:开箱即用的单机模式、自动创建集合与索引、统一的 mongosh 交互环境,学习曲线平缓是它攻城略地的头号武器。赌分布式能力内建:复制集与分片是产品核心而非外挂,第 3 章内功的产品化在这套体系里最完整。
能力侧五项值得记住:灵活文档模型(异构实体共存,加字段零迁移);原生分片与复制(水平扩展与高可用内建);二级索引体系(含复合、地理、文本、部分索引,远比"NoSQL 没索引"的刻板印象丰富);聚合流水线(服务端完成统计与变形,中等复杂度分析不必外迁);近年补齐的多文档事务(副本集与分片集群均支持)。
短板侧同样要背下来:关联查询弱——跨集合关联虽有连接阶段(见 4.7),但大数据量下代价高,深度关联是建模失败信号;内存需求高——工作集(热数据加索引)常驻内存才能保证性能,超配冷数据会引发磁盘抖动;默认写关注偏松——单节点确认即返回,主机宕机可能丢少量写入,生产必须显式配置多数确认(4.5 展开);多文档事务性能代价高——能用单文档原子性解决就别开事务。
背景:团队要开发设备资产管理应用:设备种类三十余种(属性互异)、字段持续新增、单租户设备数万、查询以"按租户定位设备后按属性筛选"为主,另有少量跨租户报表。
操作:套用本节清单论证。设备属性互异且持续新增——灵活文档模型直接命中,BSON 类型覆盖设备的位置坐标(地理类型)与传感器读数(数值类型);查询模式固定(租户 + 属性筛选)——复合索引可精确服务(4.4);跨租户报表需求弱——聚合流水线兜底即可,无需外迁分析栈;反方意见是账务结算模块也在这个应用里——评估后该模块改用关系型数据库,混合持久化(1.3)收场。
结果:设备域上 MongoDB,结算域上 PostgreSQL,两库各司其职。
解读:注意论证过程的两个动作——逐条对清单验证正面理由;主动找反方证据(哪里不该用)。选型结论的可信度取决于后者。
变式:若设备数据要支持全文语义检索,加搜索引擎双写(2.5);若设备读数频率高到按秒,另建时序库,别让主库扛时序负载。
MongoDB 的能力边界随版本变化很大,很多"MongoDB 不行"的印象其实是三四年前的版本留下的。下表是选型时最常被问到的几项能力。
| 能力 | 何时具备 | 影响 |
|---|---|---|
| 可插拔存储引擎(WiredTiger) | 3.0 | 文档级并发控制与压缩,取代早期的 MMAPv1 |
| 文档级校验规则 | 3.2 | 灵活模式下也能强制字段类型与必填 |
| 复制集内多文档事务 | 4.0 | 让"多文档原子更新"成为可选项 |
| 分片集群事务 | 4.2 | 事务能力覆盖分布式部署 |
| 时间序列集合 | 5.0 | 时序场景不必外挂专用库 |
| 列式加密(客户端字段级加密) | 4.2 起逐步完善 | 敏感字段在客户端加密,服务端只见密文 |
# 连接本地实例并切库(库与集合在首次写入时自动创建) mongosh "mongodb://127.0.0.1:27017" --quiet use demo_shop # 插入一个文档,_id 不指定时自动生成 ObjectId db.orders.insertOne({ order_no: "SO20260901001", customer_id: 90001, total_amount: 268.00, status: "PAID", items: [ { sku: "LAMP-01", name: "护眼台灯", qty: 1, price: 199.00 }, { sku: "CABLE-02", name: "Type-C 数据线", qty: 3, price: 23.00 } ], created_at: new Date() }) # 查询:按客户查订单,只返回需要的字段(投影) db.orders.find( { customer_id: 90001, status: "PAID" }, { order_no: 1, total_amount: 1, _id: 0 } ).sort({ created_at: -1 }).limit(10)
三个命令分别对应 MongoDB 的三件事:文档即记录(嵌套数组直接写)、查询用文档表达条件、投影控制返回字段。上手速度之所以快,正是因为查询语言与数据模型是同一套 JSON 结构——这也是它当年的头号竞争力。
准确的说法是"模式灵活"而非"没有模式"。MongoDB 不强制集合内文档结构一致,但可以通过文档校验规则($jsonSchema)在写入时校验必填字段与类型,也可以在应用层用 ODM 约束。推荐做法是:开发早期享受灵活,进入稳定期后逐步加上校验规则——既保留迭代速度,又避免脏数据累积。
认识了主人,第二站看它家里数据长什么样——文档、集合与数据库的三级世界。