MongoDB中同一属性引用多集合的合理数据库设计问询
MongoDB多集合引用的优化方案探讨
我在项目中常用Meteor.js,经常碰到MongoDB(或其他NoSQL数据库)里同一属性需要引用多个不同集合的情况。比如notes集合的文档结构如下:
{ _id: "XXXXXXXXXXXXXXXXXXXXXXXX", message: "This is an important message", dateTime: "2018-03-01T00:00:00.000Z", tagIds: [ "123456789012345678901234", "abcdefabcdefabcdefabcdef" ] }
这里的tagIds数组里的ID可能指向person、product或者其他note集合。
我自己想到了两种解决方案:
- 保存类型信息,把每个引用改成包含类型和ID的对象:
... tagIds: [ { type: "note", id: "123456789012345678901234", }, { type: "person", id: "abcdefabcdefabcdefabcdef", } ] ...
- 为每个目标集合单独设置字段,拆分原来的
tagIds:
... tagIdsNotes: ["123456789012345678901234"], tagIdsPersons: ["abcdefabcdefabcdefabcdef"], ...
但这两种方案都需要额外存储信息,想问问有没有更优的解决方案?
更优方案建议
1. 统一ID前缀/后缀标识类型
给不同集合的ID加上固定前缀或后缀,比如note_123456...、person_abcdef...,从ID本身直接判断所属集合,不需要额外存类型字段或拆分字段。
示例:
{ _id: "XXXXXXXXXXXXXXXXXXXXXXXX", message: "This is an important message", dateTime: "2018-03-01T00:00:00.000Z", tagIds: [ "note_123456789012345678901234", "person_abcdefabcdefabcdefabcdef" ] }
查询时拆分ID的前缀部分,就能知道要去哪个集合查找关联文档。这种方式兼顾简洁性和信息完整性,只需要在生成ID时做一点处理,文档结构不需要大改。
2. 引入中间关联集合
如果不想修改ID格式,可以创建一个中间集合(比如tagReferences),专门存储关联关系,每个文档记录noteId、targetType和targetId:
// tagReferences集合文档 { _id: "...", noteId: "XXXXXXXXXXXXXXXXXXXXXXXX", targetType: "note", targetId: "123456789012345678901234" }, { _id: "...", noteId: "XXXXXXXXXXXXXXXXXXXXXXXX", targetType: "person", targetId: "abcdefabcdefabcdefabcdef" }
这种方式适合关联关系复杂、后续可能扩展更多关联类型的场景,原notes集合保持干净,但查询时需要多一次关联查询,性能有轻微损耗,适合数据量不是特别大的场景。
3. 嵌入式文档(视场景选择)
如果关联的文档数据量小、不常更新,可以直接把关联文档的核心字段嵌入到notes的数组里,比如:
{ _id: "XXXXXXXXXXXXXXXXXXXXXXXX", message: "This is an important message", dateTime: "2018-03-01T00:00:00.000Z", tags: [ { type: "note", id: "123456789012345678901234", title: "关联笔记标题" }, { type: "person", id: "abcdefabcdefabcdefabcdef", name: "张三" } ] }
这种方式避免了跨集合查询,性能更好,但如果关联文档更新频繁,需要同步更新所有嵌入的副本,维护成本较高,适合静态或低频更新的关联数据。
方案选择建议
- 若希望文档结构简洁、不想增加额外集合,优先选ID前缀/后缀方案,实现成本低,查询逻辑简单。
- 若关联类型多、后续可能频繁扩展,或不想修改ID规则,选中间关联集合方案,扩展性更好。
- 若关联数据小且不常更新,选嵌入式文档方案,性能最优。
内容的提问来源于stack exchange,提问作者MS1
相关产品推荐
相关产品推荐

