存储/检查读取状态的最佳实践

时间:2014-04-28 09:57:51

标签: mongodb

让我们想象一下我们有一个公开(可供任何人使用)列表中的一些项目,如文章,数量为N.默认情况下,所有新文章都是未读的。文章存储在名为文章的集合中的mongodb中,每篇文章都有唯一的ID。

然后我们有P个用户。每个用户都可以阅读单篇文章,通过这样做,必须将特定文章标记为特定用户的阅读。所以必须有一些方法来存储特定用户已阅读特定文章。当然,这意味着对于某些用户来说,这篇文章可以被阅读,而对于一些未阅读的文章也是如此。

因此,在向用户显示文章列表之前,我们需要交叉检查文章的读/未读状态,并相应地显示读取的文章,让我们说解开它们。

现在,有两种方法可以处理读/未读状态。

首先是制作一个单独的集合 readstate ,并存储{article_id,user_id}对。假设默认情况下所有文章都是未读的,我们会使用此集合交叉检查文章列表,如果特定文章交叉检查成功(意味着 readstate 集合中有一对user_id和article_id,那么文章已阅读),我们将读取:true 添加到本文的输出中。

第二种方法是在每篇文章条目中添加本文中读取的user_id值数组。在输出之前,我们检查user_id中每个条目的数组中的值,如果匹配,我们将 read:true 添加到本文的输出中。

在简单的条件下,第二种方法可以更快地运行(我相信)并且将减少cpu / ram资源的工作量,但如果我们拥有数百万篇文章,数百万用户和有限的资源呢?第二种方法基于在阵列中找到某些user_id,它严重依赖于可用的RAM,对吧?如果我们没有足够的RAM,甚至可能会失败?另外,如果这个数组已经足够大,那么在这个数组上推送/弹出操作的速度有多快?

第一种方法的好处是,如果在 readstate 集合中正确编制索引条目,交叉匹配可以快速进行,并且可能会消耗较少的资源,但仍然会比第二种变体更慢

这是我的所有建议,我希望我解释它们是可以理解的。

您可以推荐哪些方法来处理此任务?为什么?

1 个答案:

答案 0 :(得分:3)

嗯,有三种方式:

  • 单独收集哪些用户已阅读哪些文章;
  • 保留,嵌入每篇文章,列出哪些用户已阅读;
  • 保留,嵌入每个用户,他们已阅读的文章列表。

哪个最快取决于您通常想知道的内容:如果对于给定的文章,您想知道哪些用户已经阅读过该文章,那么在文章中保留用户列表是回答该问题的一种非常快捷的方式,并且不保留用户的文章列表。您具体提到的用例是相反的:对于给定的用户,如果您想知道他们已经阅读了哪些文章,那么与用户保持文章列表将比保留文章的用户列表快得多。

要考虑的其他一些事项:

  • 在任一方向嵌入,每次用户阅读文章时,通过向其添加密钥来更新这两个文档中的一个,这意味着该集合中的文档大小单调增加,这就是碎片发生的方式。如果你单独保留读取事件,很可能插入到readstate集合(包括其索引)将大大超过对文章或用户的更新,并且几乎没有任何碎片。
  • 如果您正在为用户分页标题,则单独保留阅读事件可让您获取一系列阅读事件,而无需加载曾阅读过文章的每个用户或用户曾读过的每篇文章。
  • 每当你读到“文件大小单调增加”的字样时,你的下一个想法应该是“......直到它们达到16MB,然后下一次向它们添加内容的尝试将会失败。”