在MongoDB中,将帖子的所有评论保存在一个文档中是否实用?

Rom*_*man 8 mongodb

我已经阅读了基于文档的dbs的描述,例如,如果您愿意,可以在帖子的同一文档中将所有评论嵌入到帖子中:

{
   _id = sdfdsfdfdsf,
   title = "post title"
   body = "post body"
   comments = [
      "comment 1 ......................................... end of comment"
           .
           .
           n
   ]
}
Run Code Online (Sandbox Code Playgroud)

我的情况类似,每个评论可能大到8KB,每个帖子可能多达30个.

即使在同一文档中嵌入注释很方便,我想知道是否有大型文档影响性能,尤其是当MongoDb服务器和http服务器在不同的机器上运行并且必须通过LAN进行通信时?

Rem*_*iet 7

在其他人之后发布这个答案所以我将重复上面提到的一些事情.请接受第一个合适的答案,而不是这个答案.

那说有几件事需要考虑.考虑以下三个问题:

  1. 每次查询帖子时,您是否总是需要所有评论?
  2. 您想直接查询评论(例如查询特定用户的评论)吗?
  3. 您的系统使用率会相对较低吗?

如果可以回答所有问题,那么您可以嵌入comments数组.在所有其他场景中,您可能需要一个单独的集合来存储您的评论.

首先,您可以以并发安全的方式实际更新和删除注释(请参阅使用位置运算符的更新),但有些事情是您无法做到的,例如基于索引的插入.

将嵌入式阵列用于任何类型的大型集合的主要问题是移动更新问题.MongoDB为db.col.stats().paddingFactor每个文档保留一定量的填充(请参阅),以允许它根据需要增长.如果它用完了这个填充(并且它通常在你的用例中),它将不得不移动磁盘上不断增长的文档.这使得更新速度降低了一个数量级,因此是高带宽服务器的一个严重问题.一个相关但但不那么重要的问题是带宽.如果您别无选择,只能查询整个帖子及其所有评论,即使您只显示前10条,也会浪费相当多的带宽,尤其是云环境中的问题(您可以使用$切片以避免其中的一些).

如果你想嵌入这里是你的基本操作:

添加评论 :

db.posts.update({_id:[POST ID]}, {$push:{comments:{commentId:"remon-923982", author:"Remon", text:"Hi!"}}})
Run Code Online (Sandbox Code Playgroud)

更新评论:

 db.posts.update({_id:[POST ID], 'comments.commentId':"remon-923982"}, {$set:{'comments.$.text':"Hello!"}})
Run Code Online (Sandbox Code Playgroud)

删除评论

db.posts.update({_id:[POST ID], 'comments.commentId':"remon-923982"}, {$pull:{comments:{commentId:"remon-923982"}}})
Run Code Online (Sandbox Code Playgroud)

所有这些方法都是并发安全的,因为更新标准是(进程范围)写锁定的一部分.

尽管如此,你可能想要一个专门的收藏品供你评论,但还有第二选择.您可以将每个评论存储在专用文档中,也可以使用评论桶,例如每个评论20-30条(详见http://www.10gen.com/presentations/mongosf2011/schemascale).这有利有弊,因此您可以自行决定哪种方法最适合您想要做的事情.如果你的评论每篇文章的评论可能会超过几百,因为你需要的跳过(N)光标方法的o(N)性能,我会去寻找桶.在所有其他情况下,只需对每个文档方法进行评论.对于其他用例的评论查询也是最灵活的.


mne*_*syn 5

这在很大程度上取决于您想要允许的操作,但单独的集合通常更好。

例如,如果您想允许用户编辑或删除评论,将评论存储在单独的集合中是一个非常好的主意,因为这些操作很难或不可能单独使用原子修饰符来表达,并且状态管理变得很痛苦。该文档还涵盖了这一点

嵌入评论的一个关键问题是您将拥有不同的作者。通常,博客文章只能由博客作者修改。可以说,通过嵌入的注释,读者还可以获得对对象的写访问权限。

像这样的代码会很危险:

post = db.findArticle( { "_id" : 2332 } );
post.Text = "foo";
// in this moment, someone does a $push on the article's comments
db.update(post);
// now, we've deleted that comment
Run Code Online (Sandbox Code Playgroud)


Jul*_*ann 0

简短的回答:是的,也不是。

假设您正在写一个基于 mongoDB 的博客。您可以将您的评论嵌入到您的帖子中。

原因:查询很容易,您只需执行一次请求即可获取需要显示的所有数据。

现在,您知道您将获得带有子文档的大型文档。由于您需要通过 LAN 为它们提供服务,我强烈建议您将它们存储在不同的集合中。

原因:通过网络发送大型文档需要时间。我想,在某些情况下,您不需要每个子文档。

TL;DR:两种变体都有效。我建议您将评论存储在单独的表中。