【问题标题】:query on many to many relation mongodb database struct查询多对多关系 mongodb 数据库结构
【发布时间】:2013-09-29 03:22:33
【问题描述】:

我在 MongoDB 中有两个集合:一个保存博客的帖子数据,另一个保存具有以下模式的博客评论数据。如何使用 nodejs 和 mongoose 查询所有评论属于它的帖子并响应单页应用程序?谢谢!

var PostSchema = mongoose.Schema({
    created: {
        type: Date,
        default: Date.now
    },
    content: {
        type: String,
        default: '',
        trim: true
    },
    user: {
        type: Schema.ObjectId,
        ref: 'user'
    }
 }); 

 var CommentSchema = mongoose.Schema({
    created: {
        type: Date,
        default: Date.now
    },
    content: {
        type: String,
        default: '',
        trim: true
    },
    ofpost: {
        type: Schema.ObjectId, 
        ref: 'post'           //which post this comment belong to
    },
    user: {
        type: Schema.ObjectId,
        ref: 'user'
    }
 }); 




    var Post = mongoose.model('Post', PostSchema);
    var Comment = mongoose.model('Comment', CommentSchema); 

//example:the Comment1 and Comment2 belong to Post1
    var Post1 = new Post({ content: 'good day', user: 'John' });
    var Comment1 = new Comment({content: 'yeah', ofpost: Post1._id, user:'Tom'})
    var Comment2 = new Comment({content: 'agree', ofpost: Post1._id, user:'Tina'})

【问题讨论】:

  • 你能解释一下CommentSchema中的ref: 'post'吗?
  • 嗨@Amol M Kulkarni,我基于上述模式创建了两个模型,如下所示: var Post = mongoose.model('Post', PostSchema); var Comment = mongoose.model('Comment', CommentSchema);这是两个集合: var Post1 = new Post({ content: 'good day', user: 'John' }); var Comment1 = new Comment({content: 'yeah', ofpost: Post1._id, user:'Tom'}) var Comment2 = new Comment({content: 'agree', ofpost: Post1._id, user:'Tina' }) 所以 Comment1 和 Comment2 属于 Post1
  • 根据您的 cmets var Post1 = new Post({ content: 'good day', user: 'John' }); 没有 _id 字段;但是您将其用作参考,var Comment1 = new Comment({content: 'yeah', ofpost: Post1._id , user:'Tom'});。在您的架构中修复它,并在您的问题中更新。
  • 我们保存后,mongodb会自动渲染_id。我已经做到了,而且有效。我的问题是我不知道如何将帖子和评论放在一起来回复客户。
  • 您说“多对多”,但看起来每条评论都属于一个帖子——是这样吗?所以一个帖子可以有很多个cmet,但是一个评论只属于一个帖子。因此,“帖子到 cmets”的关系是“一对多”。对吗?

标签: node.js many-to-many schema mongoose single-page-application


【解决方案1】:

由于 mongodb 是 NoSQL 类型的数据库,并且没有 JOIN 或文档之间的任何关系,因此您必须注意这些。
一般有两种方法:

缓存
考虑将 cmets 数据存储在博客文档中。您可以毫无问题地嵌入文档。实际上,它会导致一些额外的缓存,例如 cmets 计数、cmets 的用户 ID 数组和其他内容,这些内容将使您的查询被索引,并且可以更轻松地通过集合进行搜索。

多个查询
如果您仍然需要单独的集合,那么您需要“模拟”连接。最有效的方法是对不同的集合进行临时索引数组和多个查询。通常对于一个 Join(多对多)应该只有 2 次查询,以及将第二个查询文档添加到第一个文档数组的小迭代。

以下是适合且仍然表现良好的流程,例如:
两个集合,第一个是posts,第二个是comments,其中有id 的帖子。

  1. 查询帖子。
  2. 遍历每个帖子并将其id 添加到postIds 数组中,同时创建postMap 对象,其中key 将是帖子的idvalue 将是特定的post。 - 这就是所谓的索引帖子。
  3. 使用$in 参数和postIds 帖子ID 数组查询comments 集合。该集合应该对 post id 字段进行索引,以使该查询非常有效。此查询还可以包括按日期排序(额外的复合索引会加快它的速度)。
  4. 遍历每条评论并使用 postMap 将其添加到帖子的 cmets 数组中。

所以我们只有 2 个查询,并且通过所有 cmets 进行一次迭代,以将数据嵌入帖子 O(n)。如果没有第二步,添加到帖子可能会是 O(p*c),其中 p - 帖子数和 c - cmets 数。这显然要慢得多,大查询也可能很慢。

总结
从数据的角度来看,第二种方法更易于管理,在writes 上也更容易,而在reads 上更复杂。
仍然需要一些缓存,例如博客帖子的 cmets 数量。

【讨论】:

  • 缓存:很好,但是如果我们对一个帖子有 1000 条评论,这是不可能的 多个查询:这是我正在做的方式,但我将 nodejs 用于服务器端,并且 nodejs 进程是异步的过程中,我们无法添加任何内容,如您所说的“使用 postMap 将其添加到 cmets 帖子数组”。先看看我的问题:link
  • 另一个链接:link
  • 以上链接,我用人代替帖子,用产品代替评论。一个人可以买多种产品
  • 您发布的链接中的问题是,i 的回调与分配此回调时的回调不同,这就是您无法正确获取它们的原因。您需要了解 JS 中带有异步回调的迭代器和变量范围。在此处查看文章:tobyho.com/2011/11/02/callbacks-in-loops
猜你喜欢
  • 2022-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 2023-03-05
  • 2019-08-31
相关资源
最近更新 更多