MongoDB 和 Mongoose:文档引用 ID 的嵌套数组

Nic*_*wyn 1 javascript relationship mongoose mongodb node.js

我一直在深入研究 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
});
Run Code Online (Sandbox Code Playgroud)

和被引用的孩子:

//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
  }
});
Run Code Online (Sandbox Code Playgroud)

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

这似乎非常低效。我的问题有两个:

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

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

预先感谢您的洞察力!

Neu*_*der 7

关于你的第一个问题:

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

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

关于你的第二个问题:

与变体 A 相比的好处是,例如,您可以获取帖子,并立即知道它有多少评论,而无需要求 mongodb 浏览可能的成百上千的文档。

相对于变体 B 的好处是,由于 mongos 16MB 的文档大小限制,您可以在单个文档(单个帖子)中存储更多对评论的引用,而不是整个评论。


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

  • 如果文档会被读取很多,写入的不多,并且它不太可能大于 16MB:嵌入子文档。通过这种方式,您可以在单个查询中获取所有数据。

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

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

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

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