首先,我只想说我是mongoDb新手,来自关系“哲学”,可能是我对mongoDb工作方式的一些假设可能是错误的。我正在开发一个简单的项目,使用平均堆栈,这是一个简单的讨论系统,在这里你有主题和帖子。
为了在MongoDB中建模这个用例,我想出了3种方法:
{ topicId : ObjectId, postsNr : Number, posts : [{POST},{}] }正如我将这些选项理解为一些缺点一样,posts的数量可能会很大,比如说50万个,而且推拉数组中的元素会影响性能,因为填充因素会影响性能。此外,与单独的集合相比,嵌入式文档在排序和范围查询方面提供的灵活性更低。但是,对于使用聚合框架、'$‘操作符和$slice的内容,可以对数组中的特定帖子进行排序、更新和分页,如果我错了,请纠正我。
{ topicId : ObjectId, postsNr : Number, }
{ postId : ObjectId, topicId : ref for topicId, }使用这样的东西提供了更多的灵活性,但知道这是一个困扰我的问题。想象一下这个简单的场景,一个用户发了个帖子,知道我想要执行对数据库的不同的写操作,一个在post集合中插入post,另一个在Topics集合中插入$inc postsNr。知道MongoDb不提供事务--我可能会插入post,然后出错,postsNr也不会增加,从我的数据上知道将是MongoDb,而且我看到的不是最终不一致的,因为它将不再一致。
这让我想到,也许我在用MongoDB作为一个不合适的用例,而关系数据库将是一个更好的选择,但是MongoDB的快速写入和性能使我认为它可能是解决这个问题的一个很好的备份。
为了减轻这个问题,我想出了一个新的设计,但由于缺乏蒙戈的经验,我不确定它的正确性。
{ topicId : ObjectId, postsNr : Number, recentPostsNr : Number, recentPosts : [{},{}], //Keeps the "X" recent posts, let's say 200 }
{ postId : ObjectId, topicId : ref for topicId }在这里,我将200个最新的帖子存储在主题集合中,每次新的帖子出现时,它都存储在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移动到post集合,所以我只做了一次,在执行findAndMofidy()查询之前出现了一些问题,下次当一个post被插入时,它将执行相同的操作,因为recentPostsNr仍然是200,但是不会发生任何事情,因为$addToSet不会改变任何东西。这一次执行findAndModify()并更新recentPosts数组和recentPostsNr,然后插入新的post并增加postsNr。
就像我说的,我在蒙戈没有经验来判断这是否真的有效,或者我是不是错过了什么。这让我认为,在MongoDb中,如果您需要链接文档,那么它并不是解决问题的最佳选择,除非数据一致性不是问题。这将我引向本文:http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/
不好意思,很长的帖子,但也许更多的MongoDB初学者有同样的疑问,我的,你的答案可以帮助消除他们。
谢谢
发布于 2015-04-24 13:12:15
很难摆脱你以前所有的关系思维方式。
首先讨论第三个选项(两个集合),在我看来只使用一个。在归档文件上保留时间戳,如果需要最后一个X值,则限制排序查询。拥有两个相同的集合是不必要的,增加了复杂性。
第二个想法,一个更多的“关系”也是混乱的,你将不得不做2查询,因为缺乏连接在芒果,你可以节省工作,如果你只这样做一个。
第一个是最好的,但我认为,为了保存positionNr,它是很难的,可以用持久性的时间戳来替换(再次)。这总是保持秩序,你可以通过计数得到位置。另外,一个帖子可以有多个主题(我不确定某个主题是像论坛中的一个线程,还是像一个帖子的标签),您可以考虑将文章保存为主文档,主题位于这样的字段中:
{
postContent: {[...]},
timestamp: ISODATE("..."),
topic/topics :[X1,X2,...]
}并在主题中保留索引,以提高主题帖子的搜索速度。
https://stackoverflow.com/questions/29847741
复制相似问题