MongoDB 和 Mongoose:文档引用 ID 的嵌套数组
MongoDB and Mongoose: Nested Array of Document Reference IDs
我一直在深入研究 MongoDB,发现了一种特别有趣的模式,用于存储文档之间的关系。此模式涉及包含引用 child 文档的 ID 数组的 parent 文档,如下所示:
//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:
//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(以更新 post)和新的 Comment,这对于使用普通关系数据库时发送的请求来说都是常见的。将新 Comment 写入数据库时会出现此问题。而不是一个数据库写入,就像你在普通关系数据库中所做的那样,我必须做 2 次写入和 1 次读取。第一个写入插入新 Comment 并检索 _id。然后通过随请求发送的 Post _id 读取以检索 Post,这样我就可以将新的 Comment _id 推送到嵌套引用数组。最后,最后一次写入将 Post 更新回数据库。
这看起来效率极低。我的问题是 two-fold:
是否有 better/more 有效的方法来处理这种关系模式(parent 包含一个 child 引用 ID 数组)?
如果不是,使用此模式与 A) 将 parent _id 存储在 child 类似的 属性 中有什么好处到传统的外键,或 B) 利用 MongoDB 文档并存储评论数组,而不是评论的引用 ID 数组。
提前感谢您的见解!
关于您的第一个问题:
您特别要求一种更好的方法来处理存储在父项中的子 ID。如果必须采用这种模式,我很确定没有更好的方法来处理这个问题。
但是这个问题也存在于关系型数据库中。如果您想将 post 保存在关系数据库中(使用该模式),您还必须首先创建评论,获取其 ID,然后更新 post。当然,您可以在一个请求中发送所有这些任务,这可能比使用猫鼬更有效,但需要完成的工作类型是相同的。
关于你的第二个问题:
与变体 A 相比的好处是,例如,您可以获得 post,并立即知道它有多少评论,而无需要求 mongodb 浏览可能成百上千的文档。
与变体 B 相比的好处是,与 相比,您可以在单个文档(单个 post)中存储更多 对评论的引用 整个 评论,因为 mongos 16MB 文档大小限制。
然而,缺点是您提到的缺点,即维护该结构效率低下。我认为这只是展示场景的示例,所以我会这样做:
我会根据具体情况决定使用什么。
如果文档被读取的次数很多,写入的次数很少,AND 它不太可能超过 16MB:嵌入子文档.这样你就可以在一个查询中获取所有数据。
如果你需要引用来自多个其他文档的文档AND你的数据确实必须一致,那么你别无选择,只能引用它。
如果您需要从多个其他文档中引用该文档但是数据一致性并不是那么重要AND 第一个要点的限制适用,然后嵌入子文档,并编写代码以保持数据一致。
如果您需要从 多个 其他文档中引用该文档,并且它们被写入了很多,但并不经常阅读,您可能最好引用它们,因为这样更容易编码,因为您不需要编写代码来同步重复数据。
在这种特定情况下 (post/comment) 从子对象引用父对象(让子对象知道父对象 _id
)可能是个好主意,因为它比其他方式更容易维护左右,如果直接嵌入,文档可能会增长到 16MB 以上。如果我确定文档不会超过 16MB,嵌入它们会更好,因为这样查询数据更快
我一直在深入研究 MongoDB,发现了一种特别有趣的模式,用于存储文档之间的关系。此模式涉及包含引用 child 文档的 ID 数组的 parent 文档,如下所示:
//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:
//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(以更新 post)和新的 Comment,这对于使用普通关系数据库时发送的请求来说都是常见的。将新 Comment 写入数据库时会出现此问题。而不是一个数据库写入,就像你在普通关系数据库中所做的那样,我必须做 2 次写入和 1 次读取。第一个写入插入新 Comment 并检索 _id。然后通过随请求发送的 Post _id 读取以检索 Post,这样我就可以将新的 Comment _id 推送到嵌套引用数组。最后,最后一次写入将 Post 更新回数据库。
这看起来效率极低。我的问题是 two-fold:
是否有 better/more 有效的方法来处理这种关系模式(parent 包含一个 child 引用 ID 数组)?
如果不是,使用此模式与 A) 将 parent _id 存储在 child 类似的 属性 中有什么好处到传统的外键,或 B) 利用 MongoDB 文档并存储评论数组,而不是评论的引用 ID 数组。
提前感谢您的见解!
关于您的第一个问题:
您特别要求一种更好的方法来处理存储在父项中的子 ID。如果必须采用这种模式,我很确定没有更好的方法来处理这个问题。
但是这个问题也存在于关系型数据库中。如果您想将 post 保存在关系数据库中(使用该模式),您还必须首先创建评论,获取其 ID,然后更新 post。当然,您可以在一个请求中发送所有这些任务,这可能比使用猫鼬更有效,但需要完成的工作类型是相同的。
关于你的第二个问题:
与变体 A 相比的好处是,例如,您可以获得 post,并立即知道它有多少评论,而无需要求 mongodb 浏览可能成百上千的文档。
与变体 B 相比的好处是,与 相比,您可以在单个文档(单个 post)中存储更多 对评论的引用 整个 评论,因为 mongos 16MB 文档大小限制。
然而,缺点是您提到的缺点,即维护该结构效率低下。我认为这只是展示场景的示例,所以我会这样做: 我会根据具体情况决定使用什么。
如果文档被读取的次数很多,写入的次数很少,AND 它不太可能超过 16MB:嵌入子文档.这样你就可以在一个查询中获取所有数据。
如果你需要引用来自多个其他文档的文档AND你的数据确实必须一致,那么你别无选择,只能引用它。
如果您需要从多个其他文档中引用该文档但是数据一致性并不是那么重要AND 第一个要点的限制适用,然后嵌入子文档,并编写代码以保持数据一致。
如果您需要从 多个 其他文档中引用该文档,并且它们被写入了很多,但并不经常阅读,您可能最好引用它们,因为这样更容易编码,因为您不需要编写代码来同步重复数据。
在这种特定情况下 (post/comment) 从子对象引用父对象(让子对象知道父对象 _id
)可能是个好主意,因为它比其他方式更容易维护左右,如果直接嵌入,文档可能会增长到 16MB 以上。如果我确定文档不会超过 16MB,嵌入它们会更好,因为这样查询数据更快