MongoDB 是文档数据库的旗手。关系数据库讲了半个世纪的"先范式化拆表、再 join 拼装",它的回答简单直接:应用里数据长什么样,库里就存什么样。到了 2026 年,8.0 系列仍在稳定迭代,向量搜索也走进了自建社区版,这门技术依然值得从零学一遍。本文按"概述、建模直觉、安装、CRUD 与聚合、索引、向量搜索、选型、实战"的顺序组织全文。
1、MongoDB 概述与现状
先给版本结论:8.0 是当前主版本线,2024 年 10 月正式发布(GA),合并了此前 7.1 至 7.3 三个快速发布版的全部变更;截至 2026 年 10 月,补丁版本已迭代到 8.0.34,官方定位为生产就绪的推荐升级目标,细节见 8.0 发布说明。8.0 这一版的主线是性能与时延:查询执行时间、并发写入吞吐、复制延迟都有可观测改进,具体数字以官方文档为准。
再讲协议口径,这是绕不开的话题。MongoDB 自 2018 年 10 月起从 AGPL 切换到 SSPL(Server Side Public License)。SSPL 是"源码可用"协议,不是 OSI 认证的开源协议:自己部署、嵌入自己的产品都免费,但若把数据库本身作为服务对外售卖,需要开放整个服务栈的源码,口径详见 SSPL 官方 FAQ。这一协议让 Red Hat、Debian 等发行版停止收录新版本,也催生了 FerretDB 这类兼容替代品。
那 2026 年还值得学吗?值得,三个理由:
- 文档模型与关系模型并列为主流建模范式,存量系统体量巨大
- 各语言驱动成熟,官方文档与教程体系完整,上手成本低
- 向量搜索 2025 年下半年落地自建社区版,AI 应用可复用同一套库
现状速览如下:
| 项目 | 现状 |
|---|---|
| 主版本线 | 8.0,2024 年 10 月正式发布 |
| 补丁节奏 | 约每月一次,2026 年 10 月至 8.0.34 |
| 协议 | SSPL,源码可用,自建免费 |
| 向量搜索 | Atlas 托管成熟,社区版自建可用 |
2、文档模型直觉
文档模型的核心直觉只有一句话:数据的存储单元与应用的读写单元保持一致。以电商商品为例:一个商品页需要名称、价格、规格、标签和几条精选评论,关系建模要把它们拆进商品、标签、规格、评论多张表再 join 拼装,文档建模则整体存成一个 JSON 文档。
两种建模路径对比如下:
图中左侧是范式化路径,写时拆散、读时拼装;右侧整存整取,商品页一次读取全部拿到。一个典型的商品文档长这样:
{
"_id": "p1001",
"name": "机械键盘 K870",
"price": 399,
"specs": { "layout": "87 键", "switch": "红轴" },
"tags": ["外设", "键盘"],
"reviews": [
{ "user": "quibbler", "stars": 5, "text": "手感极佳" }
]
}
specs、tags、reviews 在关系模型里各是一张关联表,这里全是文档内部的字段与数组,不需要任何 join。两种模型的差异归纳如下:
| 维度 | 关系模型 | 文档模型 |
|---|---|---|
| 数据形状 | 多表范式化 | 与应用对象一致 |
| 读取方式 | join 拼装 | 单文档整取 |
| 结构变更 | 改表结构再迁移 | 直接写入新字段 |
| 原子边界 | 跨表事务 | 单文档天然原子 |
要警惕的反模式也来自同一个直觉:数组无限增长。单文档上限 16 MB,且任何更新都会重写整个文档,评论这种只增不减的数据塞进商品文档迟早出事,第 8 节专门拆解这个取舍。
3、Docker 安装启动
本地学习环境用 Docker 最省事,一条命令起一个 8.0 实例并挂载数据卷:
docker run -d --name mongo8 \
-p 27017:27017 \
-v mongo-data:/data/db \
mongo:8
mongo:8 会拉取 8.0 系列的最新补丁版,-v 把数据放进命名卷,容器删掉数据仍在。接着进入交互 shell 验证版本:
docker exec -it mongo8 mongosh
进入后执行 db.version(),撰写时输出 8.0.34,与拉取的镜像补丁版一致。mongosh 是官方新一代 shell,支持自动补全与多行编辑;老的 mongo CLI 在 6.0 已被移除,旧教程里的写法要留个心眼。
4、CRUD 与聚合管道
4.1、find 与 update 基础
增删改查(CRUD)四件套在 mongosh 里的最小用法如下:
// 插入一个商品
db.products.insertOne({ name: "显示器 X27", price: 2199, tags: ["外设"] })
// 查询:标签含"外设"且价格低于 1000
db.products.find({ tags: "外设", price: { $lt: 1000 } })
// 更新:$set 只改指定字段,避免整文档替换
db.products.updateMany(
{ name: "机械键盘 K870" },
{ $set: { price: 349 } }
)
// 删除
db.products.deleteOne({ _id: "p1001" })
查询条件本身就是一个 JSON 形状的"查询文档",$lt、$in、$regex 等操作符可以自由组合。更新必须通过 $set 这类更新操作符——直接传值会替换整个文档,这是新手最常见的翻车点。
4.2、聚合管道实战
聚合管道(aggregation pipeline)是 MongoDB 的灵魂:文档像水流过一串阶段,每个阶段变换一次。一个实用例子——统计价格 100 元以上商品中出现频次前五的标签及其平均价格:
db.products.aggregate([
{ $match: { price: { $gte: 100 } } },
{ $unwind: "$tags" },
{ $group: {
_id: "$tags",
count: { $sum: 1 },
avgPrice: { $avg: "$price" }
}},
{ $sort: { count: -1 } },
{ $limit: 5 }
])
$match 先过滤缩小数据量,$unwind 把 tags 数组拆成多条记录,$group 按标签分组统计,最后排序截断。"过滤、展开、分组、排序"这个骨架能覆盖八成分析需求。现代演进也值得知道:新版加入的 $rankFusion 阶段原生实现 RRF(Reciprocal Rank Fusion,倒数排名融合),能把全文检索与向量检索两条子管道的结果合并成统一榜单,混合检索不再依赖应用层拼装,第 6 节展开。
5、索引与性能要点
没有索引的查询就是全集合扫描,数据量一大性能立刻崩。三类索引覆盖绝大多数场景:
- 单字段索引:
{ price: 1 }升序、-1降序,最基础 - 复合索引:多字段组合,字段顺序遵循 ESR 法则
- 文本索引:对字符串字段建全文检索能力
复合索引的 ESR 法则是等值过滤字段在前、排序字段居中、范围字段在后。示例如下:
// 复合索引:先按标签等值命中,再按价格排序
db.products.createIndex({ tags: 1, price: -1 })
// 文本索引:name 字段支持全文检索
db.products.createIndex({ name: "text" })
// 验证执行计划
db.products.find({ tags: "外设" }).sort({ price: -1 })
.explain("executionStats")
看 explain 输出抓两个关键点:winningPlan 里是 IXSCAN(索引扫描)还是 COLLSCAN(全表扫描);totalDocsExamined 与 nReturned 的比值越接近 1 越健康。
注意:
$lookup在大表上的关联开销显著,建模阶段就应避免高频 join;确需关联时,先给关联字段建索引,并用小数据量实测验证。
另外两条实践:索引有写放大成本,不是越多越好,单集合建议控制在个位数;索引遵循最左前缀原则,{ tags: 1, price: -1 } 只能加速以 tags 开头的查询。
6、向量搜索能力
AI 应用的语义检索需要向量近邻搜索。MongoDB 的答案是把向量直接存进文档:给集合加一个 embedding 数组字段,建向量索引,用 $vectorSearch 聚合阶段查询,与普通查询、聚合无缝组合。查询写法如下:
db.products.aggregate([
{ $vectorSearch: {
index: "vec_idx",
path: "embedding",
queryVector: qvec, // 查询文本转向量后的数组
numCandidates: 200,
limit: 10
}},
{ $project: { name: 1, score: { $meta: "vectorSearchScore" } } }
])
numCandidates 控制候选集大小,是召回率与时延之间的调节旋钮;$meta 取出相似度得分参与投影,命中结果直接带出商品名。两条获取路径对比如下:
| 方案 | 说明 |
|---|---|
| Atlas 托管 | Vector Search 全托管,索引与检索成熟稳定,按量计费 |
| 社区版自建 | 2025 年 9 月起公开预览,2026 年可本地跑通 |
自建路径的关键节点:官方在 2025 年 9 月 宣布 全文搜索与向量搜索进入 Community Edition 公开预览,2026 年社区版已能在本地容器里建向量索引并执行 $vectorSearch,详见 Vector Search 文档。对 AI 工程师的意义在于向量、原文、业务字段同库:检索命中后直接 $project 出价格与库存,不必再回查独立的向量库,一致性由单库保证。混合检索则交给 $rankFusion:全文与向量两条子管道各排各的,RRF 公式融合出统一榜单。
7、选型边界决策
2026 年的选型共识其实很收敛:没有特殊理由时默认关系库(PostgreSQL),出现明确特征再考虑文档库。PostgreSQL 的 JSONB 同样能存文档,事务与 join 能力更强,"拿不准就选它"很少出错。适合文档库的场景判断如下:
| 场景特征 | 建议 |
|---|---|
| 字段多变、结构快速演进 | 文档库占优 |
| 嵌套深、整存整取 | 文档库占优 |
| 高写入吞吐、水平分片 | 文档库占优 |
| 多表复杂 join 与报表 | 关系库占优 |
| 强一致的跨表事务为主 | 关系库占优 |
| 拿不准 | 先用 PostgreSQL |
性能传闻要泼一盆冷水:公开基准显示常规负载下两者的写入吞吐在同一量级,文档库并不天然更快。选型的依据是数据形状与访问模式,不是性能神话。
8、实战评论系统建模
商品评论是文档建模的经典考题:评论与商品天然亲和,但评论量会无限增长。两种方案都摆出来看。
8.1、嵌入式建模
评论作为数组直接嵌入商品文档:
{
"_id": "p1001",
"name": "机械键盘 K870",
"review_count": 2,
"reviews": [
{ "user": "alice", "stars": 5, "text": "手感好", "date": "2026-10-01" },
{ "user": "bob", "stars": 4, "text": "键帽易打油", "date": "2026-10-02" }
]
}
优点是商品页一次读取全部拿到,最新几条评论零成本展示。致命伤在容量:热门商品几十万条评论必然撑爆 16 MB 上限,且每条新评论都触发整文档重写,写放大不可接受。
8.2、引用式建模
评论独立成集合,商品文档只留统计摘要:
// products:只留聚合摘要,读多写少
{ "_id": "p1001", "name": "机械键盘 K870",
"rating_avg": 4.5, "review_count": 2 }
// reviews:独立集合,支持分页与审核流
{ "product_id": "p1001", "user": "alice", "stars": 5,
"text": "手感好", "status": "approved", "date": "2026-10-01" }
分页、审核、按用户查评论都变成对 reviews 集合的普通索引查询;摘要字段用写入时增量更新或定时任务维护。两种方案的取舍对照:
| 维度 | 嵌入式 | 引用式 |
|---|---|---|
| 商品页读取 | 一次搞定 | 两次查询 |
| 评论容量 | 16 MB 硬顶 | 无限制 |
| 写入成本 | 整文档重写 | 单条插入 |
| 独立运营 | 不支持 | 审核分页自如 |
结论:只展示最新几条且评论量小时可嵌入,正经评论系统一律引用式加摘要冗余。这也是文档建模的通用心法——聚合边界之内嵌入,边界之外引用。
9、总结
回顾全文:8.0 是当前主线,SSPL 自建免费;文档模型的直觉是存储单元对齐读写单元;聚合管道用"过滤、展开、分组、排序"骨架覆盖大多数分析;复合索引记住 ESR 法则;向量搜索已可在社区版自建,$rankFusion 原生支持混合检索;选型看数据形状而非性能神话;评论系统示范了嵌入与引用的边界。对于正在做技术选型的团队,建议用第 7 节的决策表过一遍自己的数据形状再决定是否引入文档库;对于学习者,用 Docker 起 8.0 实例亲手写一遍聚合,比读十篇教程都有效。
练习三道:
- 用聚合管道统计 reviews 集合中每个用户的评论数与平均星级
- 为 reviews 建包含
product_id与created_at的复合索引,用 explain 验证命中 - 把商品描述文本转为 embedding,在社区版建向量索引并跑通
$vectorSearch


