MongoDB父引用子与子引用父的优势对比及适用场景咨询
MongoDB父引用子模式的适用场景与优势
先明确你提到的两种引用模式:
子引用父(常规关系型思路)
users集合:
{ _id: ObjectId("xxx"), name: 'User Name' }
posts集合:
{ _id: ObjectId("xxx"), title : 'Post Title', userId : 'ref to user id' }
父引用子(父文档存子ID数组)
users集合:
{ _id: ObjectId("xxx"), name: 'User Name', posts : ['id1', 'id2'] }
posts集合:
{ _id: ObjectId("xxx"), title : 'Post Title' }
你担心的父引用子的问题(数组无限增长、需更新父文档)确实是普遍存在的硬伤,这也是多数场景下优先选择子引用父的原因,但父引用子并非过时方法,在特定场景下它的优势很明显:
核心优势
- 快速获取关联子项的元信息/统计数据:无需查询子集合,直接从父文档就能拿到子项ID列表,或通过数组长度快速统计子项数量,避免了
count()或聚合查询的开销。 - 简化关联逻辑:在需要以父为维度统一管理子项时,比如批量删除用户的所有子项,直接拿到父文档里的子ID数组就能批量操作,不需要先查询子集合筛选出关联数据。
适用场景
父引用子只适合子项数量明确有限、不会无限增长的场景,典型例子包括:
- 用户的常用地址、收藏夹(通常有数量上限)
- 用户的权限列表、角色关联
- 商品的标签列表(标签数量不会过多)
实际示例:用户常用地址管理
这个场景下,用户的地址数量一般不会超过10个,完全不会触发MongoDB的16MB文档限制:users集合:
{ _id: ObjectId("60d21b4667d0d8992e610c85"), name: "张三", defaultAddressId: ObjectId("60d21b8967d0d8992e610c86"), addressIds: [ObjectId("60d21b8967d0d8992e610c86"), ObjectId("60d21ba367d0d8992e610c87")] }
addresses集合:
{ _id: ObjectId("60d21b8967d0d8992e610c86"), detail: "北京市朝阳区XX街道XX号", phone: "138XXXXXXX" }, { _id: ObjectId("60d21ba367d0d8992e610c87"), detail: "上海市浦东新区XX路XX号", phone: "139XXXXXXX" }
在这个场景中:
- 要统计用户的地址数量,直接取
addressIds.length即可,无需查询addresses集合 - 要获取用户的所有地址ID,直接从父文档拿到数组后,用
$in批量查询地址详情,仅需2次查询 - 设置默认地址时,仅需更新
users文档的defaultAddressId字段,逻辑简洁
总结
父引用子不是MongoDB的旧方法,而是一种场景化的设计模式——当子项数量可控,且需要频繁从父维度快速获取关联子项的元数据时,它的效率会比子引用父更高;但如果子项数量会无限增长(比如用户的帖子、订单),子引用父仍是更稳妥的选择。
内容的提问来源于stack exchange,提问作者Mertafor
相关产品推荐
相关产品推荐

