3. 数据建模通用方法论
MongoDB 的文档模型设计不是“把表换成集合”这么简单。关系型建模以消除冗余、保证范式为目标,而文档建模的核心目标是:让最常见的查询用最少的读写次数、最小的文档体积完成。因此,从业务需求到最终文档模型,需要经过一条可复用的映射链路:实体识别 → 关系分析 → 访问模式梳理 → 模式设计决策。这条链路不是一次性瀑布,而是“先按访问模式定形状,再用实体和关系校验完整性”的迭代过程。
第一步:实体识别——从业务名词到候选文档
实体识别的输入是业务需求描述、领域术语表和现有系统接口。做法是:把需求中反复出现、有独立生命周期、需要被单独查询的名词圈出来,作为候选实体。例如一个“商品评论与点赞”需求,候选实体包括:用户(User)、商品(Product)、评论(Comment)、点赞记录(Like)。
识别时要区分三类名词:核心实体(有独立标识和生命周期,如 User、Product)、值对象(依附于实体、不需要独立查询,如评论里的“评分 5 星”“图片 URL 列表”)、事件/流水(只追加、按时间查询,如点赞记录、浏览日志)。值对象通常内嵌,事件流水通常独立集合。这一步的产出是一张候选实体清单,每个实体标注:唯一标识、预估量级、读写比例、是否高频更新。
第二步:关系分析——判定 1-1、1-N、N-N 与聚合边界
关系分析决定“谁内嵌谁、谁引用谁”。判定依据是三个问题:子对象是否总随父对象一起读取?子对象数量是否有界?子对象是否被独立查询或独立更新?
- 1-1:通常内嵌,如用户与其账户设置。
- 1-N(N 有界且随父读):内嵌数组,如商品与其 5 张主图。
- 1-N(N 无界或需独立查询):父存子引用或子存父引用,如商品与评论。
- N-N:用引用数组或中间集合,如用户与关注列表。
这里要引入 MongoDB 的关键约束:单个文档上限 16MB。若子对象无界增长(如一条商品的评论可能上百万),内嵌必然撑爆文档,必须拆成独立集合。因此关系分析的产出是:每个关系的基数、方向、是否内嵌、内嵌后的预估文档大小。
第三步:访问模式梳理——把“怎么查”写成清单
访问模式(Access Pattern)是文档建模真正的设计输入。它描述的是:谁、在什么场景、以什么条件、查什么字段、排序方式、返回多少条、频率多高。建议用一张访问模式表来固化,例如:
| 编号 | 操作 | 查询条件 | 排序 | 返回量 | 频率 |
|---|---|---|---|---|---|
| AP-01 | 查看商品详情 | productId | — | 1 条 | 极高 |
| AP-02 | 查看商品评论首页 | productId | createdAt 倒序 | 20 条 | 高 |
| AP-03 | 查看我的评论 | userId | createdAt 倒序 | 20 条 | 中 |
| AP-04 | 点赞/取消点赞 | userId+commentId | — | 写入 | 高 |
| AP-05 | 统计评论点赞数 | commentId | — | 1 个计数 | 高 |
梳理访问模式时,要特别标注高频、低延迟的查询,它们决定索引和文档形状;低频的统计类查询可以接受聚合管道或离线计算。同时要标注哪些字段需要排序、哪些需要范围过滤,因为 MongoDB 的复合索引遵循 ESR 原则(Equality → Sort → Range)。
第四步:模式设计决策——内嵌、引用与混合
把前三步的结论汇总,对每个关系做决策。以“商品-评论-点赞”为例:
- 商品与评论:评论无界增长,且 AP-02 按 productId 查、AP-03 按 userId 查,属于双向查询,因此评论独立成
comments集合,文档内同时存productId和userId,并建{productId:1, createdAt:-1}与{userId:1, createdAt:-1}两个复合索引。 - 评论与点赞:AP-05 需要高频读取点赞数,若每次
countDocuments会拖慢详情页。采用混合模式:点赞明细独立成likes集合(保证唯一性与可追溯),同时在评论文档中冗余一个likeCount字段,写入点赞时用$inc原子更新。 - 评论中的图片、评分:值对象,直接内嵌为数组和标量字段。
下面这张图展示了从业务需求到文档模型的完整映射链路,以及“商品-评论-点赞”案例中各实体的最终归属与关键索引:
决策中的常见取舍与校验
完成初版模型后,需要用三个问题做校验。第一,文档大小:估算最大文档体积,若接近 16MB 的 30% 就应警惕,考虑拆分子集合或使用 Bucket 模式。第二,写入热点:若某个文档被高频 $inc 或 $push,要评估是否会造成单文档写竞争;点赞计数这类场景可接受,但若每秒数千次更新同一文档,应考虑分片键或异步合并。第三,索引覆盖:把访问模式表逐条对照索引,确认高频查询都能走索引,且排序字段在索引中的位置符合 ESR 原则。
最后要强调,文档建模没有唯一正确答案,只有“对当前访问模式更优”的答案。同一组实体,在“读多写少”的详情页场景和“写多读少”的日志场景下,内嵌与引用的选择可能完全相反。因此,方法论的价值不在于给出固定结论,而在于提供一条可重复、可校验、可迭代的推理路径:先识别实体,再分析关系,然后用访问模式定形状,最后用大小、热点和索引三项校验收口。