Mongodb 关系:帖子和评论(参考 v 子文档)

Posted

技术标签:

【中文标题】Mongodb 关系:帖子和评论(参考 v 子文档)【英文标题】:Mongodb Relationship: Posts and Comments (ref v sub-documents) 【发布时间】:2020-12-22 12:13:18 【问题描述】:

我知道有很多类似的问题,但它们太老了,因为 Mongodb 在过去 5-6 年里已经发展了很多,我正在寻找一个好的模式设计。

目标:我希望有一个用户与 cmets 的帖子。

到目前为止我的设计是:

单独的post模型:
const projectSchema = new mongoose.Schema(
    user:  type: mongoose.Schema.Types.ObjectId, required: true, ref: 'User' ,
    title:  type: String, required: true ,
    image:  type: String, default: undefined ,
    description:  type: String, required: true, minLength: 200, maxlength: 500 ,
    comments: [
        type: mongoose.Schema.Types.ObjectId, ref: 'Comment'
    ],
    state:  type: Boolean, default: true ,
    collaborators:  type: Array, default: [] ,
    likes:  type: Array, default: [] 
)
还有一个单独的 cmets 模型:
const commentSchema = new mongoose.Schema(
    comment:  type: String, required: true ,
    project:  type: String, required: true, ref: 'Project' ,
    user:  type: String, required: true, ref: 'User' 
)

我选择关系方法的原因是,如果 cmets 的数量增加到 10,000 个,它将大大增加模式的大小

这样,无论我们可以使用它们的 ID 填充多少个 cmets,我们自己也会有不同的 cmets 集合。

参考:one-to-many

这对我的项目来说是个好方法吗?


我从一篇文章中查询 cmets 的方式:

const project = await Project.findById(
        new mongoose.Types.ObjectId(req.params.projectId)
    ).populate(
        path: 'comments',
        populate:  path: 'user' 
    ).lean()

【问题讨论】:

【参考方案1】:

这是否是一个好的设计取决于您期望每个帖子有多少 cmets,以及将在您的应用上执行什么查询。

mongodb.com 有一篇关于如何设计数据库架构的好博客

常见的设计是:

一对多(使用嵌入) 一对多(使用嵌入参考) 一对 squillions(通常的关系数据库一对多方法)

总结是:

因此,即使在这个基本级别上,在设计 MongoDB 架构时也需要考虑比在设计类似的关系架构时更多的考虑。您需要考虑两个因素:

One-to-N 中“N”侧的实体是否需要独立存在? 关系的基数是什么:是一对多吗?一对多;还是一对一?

基于这些因素,您可以选择三种基本的一对 N 架构设计之一:

如果基数是一对多并且不需要在父对象的上下文之外访问嵌入的对象,则嵌入 N 端 如果基数是一对多或者 N 端对象出于任何原因应该独立存在,则使用对 N 端对象的引用数组 如果基数是一对 squillions,则在 N 侧对象中使用对 One-side 的引用

还有关于高级模式设计的a blog,值得一读。


您似乎正在使用two-way referencing 方法。

你和one-to-squillions 的区别在于你不仅将post id 引用存储在评论文档中,还将评论id 作为引用存储在post 文档中,而one-to-squillions 只会将项目id 引用存储在评论文件。

如果您需要获取帖子的评论 ID,使用您的方法会更好。但缺点是您在删除或创建评论时需要运行两个查询,一个用于从帖子中删除/创建评论 ID,另一个用于删除/创建它自己的评论文档。查找“哪个帖子属于给定的评论 id”也会更慢。

虽然在执行查询以通过 post id 获取 cmets 时,使用 one-to-squillions 会降低性能。但是您可以通过正确索引您的评论集合来缓解这种情况。

【讨论】:

感谢您的简短解释。尽管我对您在有关一对多与一对数的观点中所说的话有些困惑。当我阅读它时,他们的方法听起来与我相似。如果您能区分它们各自的方法,将不胜感激。 Also,根据这个文档,为大数创建一个单独的模型看起来是一种更好的方法:=> docs.mongodb.com/manual/tutorial/… 我读错了您的架构,您似乎使用的是双向引用,而不是一对多。一对一可能更适合您的用例,请查看我编辑的答案。简而言之,这取决于将在您的应用上执行什么查询。 是的,这是故意的。我更新了答案以显示我如何查询与单个项目相关的 cmets。 原因:因为如果我们在 cmets 模型中有 1000000 个 cmets 与 1000 个不同的帖子相关,则它必须在 1000000 个 cmets 中查询一个 post _id。直接从帖子本身填充comment_id 的本地数组不是更好吗? 你说得对,各有利弊,请再次查看我编辑的答案。归结为在您的应用上执行的查询最多。

以上是关于Mongodb 关系:帖子和评论(参考 v 子文档)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 mongodb 和 mongoose 从帖子模型中计算整体帖子活动(喜欢、不喜欢、评论)和用户模型中的参考总和

插入父帖子vue js的子评论

如何更新 MongoDB 中的子文档?

E11000 MongoDB/Mongoose 重复键错误

在 MongoDB 中模拟关系

MongoDB - 查询难题 - 文档参考或子文档