Embed when data is read together in most cases

Reference when data is read together “sometimes”

  • To query normalized data in multiple collections, MongoDB provides $lookup aggregation stage

你可以尝试搜索:

  • MongoDB references vs embedding

  • MongoDB normalization vs denormalization

  • MongoDB nested documents vs separate collections

  • MongoDB schema design

  • MongoDB aggregation lookup vs embedded

总结一下也很简单, 当系统结构简单, 子文档也很小的时候, 可以不用规范化, 直接嵌套, 比如用户里面直接嵌入地址信息, 地址嘛, 也不会很大, 获取用户信息的时候, 直接一个 document 什么都有了, 减少连表查询, 速度也很快,

但系统复杂的时候, 比如多对多关系, 很多表需要相互关联, 需要经常修改, 这个时候就不可以嵌套了, 比如我们需要经常修改商品信息, 或者商品的评论信息, 这个时候就不可以采用 把 评论 嵌入 商品, 把商品嵌入商店, 因为这样, 每次你修改评论, 都需要去查找商店, 然后对应的商品, 然后去修改对应的评论, 这肯定不高效, 不如使用规范化, 直接根据评论 id 去更新数据,

MongoDB 没有传统数据库中 join 操作和 foreign key, 但可以通过 embedded documents 或者 reference 来表示一对多关系, 也可使用聚合管道 $lookup 来实现类似 Join 的功能, 但注意 $lookup 只适用于 Reference 存储的查询, 而不是嵌套文档, 上面已经给出了两种方法具体的查询方式


至于规范化的设计, 一般有两种存储

  • 商店添加一个数组字段存储拥有的商品 id
  • 商品添加一个字段, 标注其所属的 id

前者需要使用 MongoDB 的数组查询, 后者使用 $lookup 聚合管道查询, 这都是规范化的设计, 至于哪个更好, 要看具体的场景, 注意想要查询效率, 就要接受一定程度数据冗余, 当然有了冗余, 不仅仅是占用空间的问题, 还存在更新的问题, 比如商店存储其拥有的所有商品 id 或者 name 这就是冗余, 因为可以直接通过 商品 collection 查询到某个商店的所有商品, 那为什么会导致更新问题呢?

  • 当商品的名字更新的时候, 商店若存了所拥有的所有商品名字列表, 是不是也需要更新这个数组?
  • 当商品被删除下架的时候, 是不是也要处理商店的商品名字列表?