用于“主题 - >帖子”域用例

时间:2015-04-24 12:37:36

标签: node.js mongodb

首先,我只是想说我是mongoDb的新手并且来自关系“哲学”,可能我对mongoDb如何工作的一些假设可能是错误的。我正在使用MEAN堆栈开发一个简单的项目,这是一个简单的讨论系统,你有主题和帖子。

为了在MongoDB中建模这个用例,我提出了3种方法:

  1. 使用嵌入式文档

    { topicId : ObjectId, postsNr : Number, posts : [{POST},{}] }

  2. 由于我理解这个选项是一些缺点,帖子的数量可以大得多,比如500,000千,并且从阵列中推拉元素会影响性能,因为填充因子。此外,嵌入式文档在排序和范围查询方面提供的灵活性低于单独的集合。然而,对于使用聚合框架,'$'运算符和$ slice可以排序,更新数组中的特定帖子并对帖子进行分页,如果我错了就纠正我。

    1. 单独收藏

      { topicId : ObjectId, postsNr : Number, }

      { postId : ObjectId, topicId : ref for topicId, }

    2. 使用这样的东西可以提供更大的灵活性,但是知道这个问题困扰着我很多。想象一下这个简单的场景,用户发帖子,知道我想要执行不同的数据库写入,一个用于在帖子集合中插入帖子,另一个用于在主题集合中的$ inc the postsNr。知道MongoDb不提供交易可能会发生我插入帖子,然后出现问题并且postsNr没有增加,因为知道我的数据将不一致以及我能看到的内容不是最终不一致因为它不会再一致了。

      这让我觉得我可能正在使用MongoDB来处理一个不合适的用例,而关系数据库将是一个更好的选择,但MongoDB的快速编写和性能让我觉得它可能是一个很好的后台存储对于这个问题。

      为了缓解这个问题,我想出了一个新的设计,但由于缺乏mongo的经验,我不确定它的正确性。

      1. 嵌入式和单独收藏品的混合

        { topicId : ObjectId, postsNr : Number, recentPostsNr : Number, recentPosts : [{},{}], //Keeps the "X" recent posts, let's say 200 }

        { postId : ObjectId, topicId : ref for topicId }

      2. 这里我将200个最新帖子存储在Topic集合中,每次有新帖子进入时,它都存储在recentPosts数组中,然后我可以增加postsNr,这是自动完成的,因为操作是在同一个文本中完成的集合。

        知道是棘手的部分,未来的某些方面我需要将de recentPosts数组刷新到Post集合,这是我在不丢失数据的情况下做的意识。

        每次有新帖(伪代码):

         `if (recentPostsNr >= 200){
            //Now push 180 from the recentPosts array to the Posts collection with addToSet
            $addToSet()
            findAndModify() =>  remove 180 posts recentPosts {}, keep 20 for retrieving and alter the recentPostsNr to 20
          }
        
          //Push the new post to the recentPosts array and inc the posts nr
          $update($inc,$push)
        

        使用这种技术,我得到了两个世界的好处。我使用$ addToSet运算符将帖子移动到Post集合,该运算符不允许重复,所以我执行一次,并且在执行findAndMofidy()查询之前出现问题,下次插入帖子时它将执行相同的操作操作因为recentPostsNr仍然是200,但是没有任何事情会发生,因为$ addToSet不会改变任何东西。这次执行findAndModify()并更新recentPosts数组和recentPostsNr,然后插入新帖子并增加postsNr。

        就像我说我没有mongo的经验来判断这是否真的有效,或者我是否遗漏了什么。这让我觉得在MongoDb中,如果你需要链接文档,那么它不是你问题的最佳选择,除非数据一致性不是问题。这让我想到了这篇文章:http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/

        对于长篇文章感到抱歉,但也许更多的MongoDB初学者有与我相同的疑问,你的答案可以帮助消除它们。

        由于

1 个答案:

答案 0 :(得分:0)

很难摆脱以前的关系思维。

首先讨论第三个选项(两个集合),在我看来只使用一个。在字段上保留时间戳,如果需要最后的X量,请限制有序查询。拥有两个相同的集合是不必要的复杂性。

第二个想法,还有一个"关系"由于mongo中没有连接,你将不得不进行2次查询,如果只在一个中进行,你可以节省工作。

第一个是最伟大的,但是我要保存位置,这很难,并且可以用持久性的时间戳替换(再次)。这总是保持秩序,你可以通过计数获得位置。也可以是一个帖子可以有多个主题(我不确定某个主题是否像论坛中的主题或者像帖子的标签一样),你可以认为将帖子保存为主文档,主题是在这样的领域:

{ 
  postContent: {[...]},
  timestamp: ISODATE("..."),
  topic/topics :[X1,X2,...]
}

并在主题中保留一个索引,以提高搜索主题帖子的速度。