【问题标题】:MongoDB and Mongoose: Nested Array of Document Reference IDsMongoDB 和 Mongoose:文档参考 ID 的嵌套数组
【发布时间】:2017-03-19 07:31:28
【问题描述】:

我一直在深入研究 MongoDB,并遇到了一种特别有趣的模式来存储文档之间的关系。此模式涉及包含引用子文档的 id 数组的父文档,如下所示:

//Parent Schema
export interface Post extends mongoose.Document {
  content: string;
  dateCreated: string;
  comments: Comment[];
}

let postSchema = new mongoose.Schema({
  content: {
    type: String,
    required: true
  },
  dateCreated: {
    type: String,
    required: true
  },
  comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }] //nested array of child reference ids
});

以及被引用的孩子:

//Child Schema
export interface Comment extends mongoose.Document {
  content: string;
  dateCreated: string;
}

let commentSchema = new mongoose.Schema({
  content: {
    type: String,
    required: true
  },
  dateCreated: {
    type: String,
    required: true
  }
});

在我从前端发送请求以创建新评论之前,这一切看起来都很好。请求必须包含 Post _id(用于更新帖子)和新评论,这对于使用普通关系数据库时发送的请求都是常见的。将新评论写入数据库时​​会出现此问题。我必须执行 2 次写入和 1 次读取,而不是像在普通关系数据库中那样执行一次 db 写入。第一次写入以插入新评论并检索 _id。然后读取通过随请求发送的 Post _id 检索 Post,以便我可以将新的 Comment _id 推送到嵌套引用数组。最后,将 Post 更新回数据库的最后一次写入。

这似乎效率极低。我的问题有两个:

  1. 是否有更好/更有效的方式来处理这种关系模式(父级包含一组子引用 ID)?

  2. 如果不是,与 A) 将父 _id 存储在与传统外键类似的子属性中,或 B) 利用 MongoDB 文档并存储Comments 数组,而不是 Comments 的引用 id 数组。

提前感谢您的洞察力!

【问题讨论】:

  • 不要将 cmets 引用为帖子中的列表,只需在帖子的评论中使用一个引用即可。您需要它的帖子 ID,并且只写一次。检索与一个帖子相关的所有 cmets。
  • @Myonara,感谢您的反馈,非常感谢。但是,我的问题更具体地说是一个架构问题,即为什么人们会选择这种模式而不是你提到的模式,以及是否有更好的方法来实现所讨论的第一个模式。
  • 这里是 CMS 风格用例 docs.mongodb.com/ecosystem/use-cases/storing-comments 的一篇文章。这谈到了选项 B。希望它有助于为您澄清一些事情。

标签: javascript node.js mongodb mongoose relationship


【解决方案1】:

关于你的第一个问题:

您特别要求一种更好的方式来处理存储在父级中的子 ID。如果必须是这种模式,我很确定没有更好的方法来处理这个问题。

但是这个问题在关系型数据库中也存在。如果您想将您的帖子保存在关系数据库中(使用该模式),您还必须首先创建评论,获取其 ID,然后更新帖子。当然,您可以在一个请求中发送所有这些任务,这可能比使用 mongoose 更有效,但需要完成的工作类型是相同的。

关于你的第二个问题:

相对于变体 A 的好处是,例如,您可以获得帖子,并立即知道它有多少 cmets,而无需要求 mongodb 遍历可能数百个文档。

相对于变体 B 的好处是,由于 mongos 16MB,与 whole cmets 相比,您可以在单个文档(单个帖子)中存储更多对 cme​​ts 的引用文档大小限制。


但是,缺点是您提到的那个,即维护该结构效率低下。我认为这只是展示场景的一个例子,所以这就是我要做的: 我会根据具体情况决定使用什么。

  • 如果文档会被大量阅读,而不会被大量写入,并且它不太可能超过 16MB:嵌入子文档。这样您就可以在一个查询中获取所有数据。

  • 如果您需要从多个其他文档中引用文档并且您的数据确实必须一致,那么您别无选择,只能引用它。

  • 如果您需要从 多个 其他文档中引用文档 BUT 数据一致性并不是那么重要 AND 限制从第一个要点开始应用,然后嵌入子文档,并编写代码以保持数据一致。

  • 如果您需要从 多个 其他文档中引用该文档,并且它们被写入很多,但不经常阅读,那么您最好引用它们,因为这样更容易编码,因为您不需要编写代码来同步重复数据。

在这种特定情况下(帖子/评论)从孩子引用父母(让孩子知道父母_id)可能是一个好主意,因为它比其他方式更容易维护,并且文档可能如果它们直接嵌入,它们会增长到超过 16MB。如果我确定文档不会超过 16MB,嵌入它们会更好,因为这样查询数据会更快

【讨论】:

  • 感谢您的详细分析。我很感激!
猜你喜欢
  • 1970-01-01
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2020-09-15
  • 2016-10-06
  • 1970-01-01
  • 2012-10-17
相关资源
最近更新 更多