我目前正在MongoDB中开展一个项目,我希望从数据库中随机抽取新产品。但我的问题不是MongoDB特有的,我认为这是一个普通的数据库问题。
情景:
假设我们有一个产品集合(或表格)。我们还有一个用户集合(或表)。每次用户登录时,都会显示10个产品。这些产品从集合/表中随机选择。很容易,但问题是,每次用户登录时,必须提供他们从未见过的10种产品。我能想到解决这个问题的两个显而易见的方法是:
每个用户都以自己的所有产品的私人列表开头。每次他们获得这些产品之一,该产品将从其私人列表中删除。结果是,下次从之前修剪过的列表中选择产品时,它只包含新项目。
每位用户都有以前查看过的产品的私人列表。当用户登录时,他们从主列表中选择10个随机产品,将每个产品的ID与其先前查看的产品列表进行比较,如果该项目出现在先前查看的列表中,则应用程序会抛出此项目,选择新的,并迭代直到有10个新项目,然后将其添加到以前查看过的列表中。
#1的问题似乎是一种巨大的浪费。你基本上会复制n个用户的列表数据。同样删除/添加新项目到系统将是一场噩梦,因为它必须遍历所有用户。 #2似乎更可取,但它也有问题。您最终可能会对数据库进行大量额外和不必要的调用,以保证10个新产品。随着用户浏览越来越多的产品,可供选择的新产品越来越少,因此不得不抛弃一个并从DB中获取新产品的机会大大增加。
有替代解决方案吗?我的首要关注点是表现。我会放弃磁盘空间以优化性能。
答案 0 :(得分:0)
这两种方式完全浪费了主存储器和辅助存储器。 你想要展示2以前从未见过的产品,但这是真的必须吗? 如果你有很多产品10个随机产品很有可能是唯一的。
3。您可以列出10个随机产品,即使不像MySQL那样容易,但仍然不如1和2复杂。
答案 1 :(得分:0)
如果你不在乎id的序列是多么随机,你可以这样做:
创建一个仅包含产品ID和连续整数代理键列的随机表。首次登录时,在列表中的随机点启动每个客户,并循环显示该密钥所订购的列表。如果到达终点,请从顶部重新开始。
客户记录将包含他们看到的最后一个产品的单个值(来自随机列表的代理,而不是实际ID)。然后,您将在登录时拉下十个并对客户进行一次更新。当然,它不会是随机的。但是这种表种子策略是很多简单的伪随机数生成器的工作原理。
我看到的唯一问题是,如果您的产品列表增长速度超过用户登录的速度。那么他们就不会看到列表中的部分出现在他们开始的任何地方之前。即便如此,有了大量产品和非常活跃的用户,这应该比存储他们看到的所有内容更好。因此,如果产品出现在一组伪随机序列中并不重要,那么这可能非常适合您。
编辑:
如果您存储了他们开始使用的第一条记录,您仍然可以生成所有内容的列表。这将是该值与上次查看之间的所有内容。
答案 2 :(得分:0)
如何做到这一点:创建一个集合prodUser
,您将拥有该产品的ID和customersID列表(已经看过这些产品)。
{
prodID : 1,
userID : []
}
当客户登录时,您会找到尚未分配给该用户的10个prodID
db.prodUser.find({
userID : {
$nin : [yourUser]
}
})
(由于某种原因,$ not不工作:-(。我没有时间弄明白为什么。如果你愿意的话 - 请告诉我。)。向他展示他的产品后 - 你可以更新他的prodUser系列。为了减轻mongos无法找到随机元素 - 你可以随机插入元素,只需找到前10个。
一切都应该非常快。