我最近发现Mongo在命令语法中没有等同于"ORDER BY RAND()"的SQL(https://jira.mongodb.org/browse/SERVER-533)
我已经在http://cookbook.mongodb.org/patterns/random-attribute/看到了这个建议,坦率地说,在文档中添加一个随机属性就像是一个黑客.这不起作用,因为这会对我想要随机化的任何给定查询设置隐式限制.
另一个广泛给出的建议是选择一个随机索引来抵消.由于我的文档插入的顺序,这将导致其中一个字符串字段按字母顺序排列,这对我的网站用户来说不会感觉非常随机.
关于如何通过代码解决这个问题,我有几个想法,但我觉得我错过了一个更明显和原生的解决方案.有没有人对如何更优雅地解决这个问题有一个想法或想法?
How can i find random records in mongodb?
Run Code Online (Sandbox Code Playgroud)
我在stackoverflow上找到了多篇文章,但我无法理解它们.例如:
db.yourCollection.find().limit(-1).skip(yourRandomNumber).next()
Run Code Online (Sandbox Code Playgroud)
我将如何在我的代码中执行它?(收藏是用户)
User.findOne(RANDOM PLAYER).then(result) {
console.log(result);
}
Run Code Online (Sandbox Code Playgroud) 关于从收集中获取随机文档的方法的问题已被多次询问,并且有关于此主题的建议.
我需要的是从集合中获取几个随机文档,更糟糕的是 - 这些文档必须符合某些标准(过滤,我的意思).例如,我有一组文章,其中每篇文章都有一个"主题"字段.用户选择他感兴趣的主题,我的数据库必须每次以随机顺序显示相应的文章.
显然,之前讨论过的黑客行为对我没有帮助.实现我想要的唯一方法是仅查询相应的主题获取ID:
var arr = db.articles.find({topic: 3}, {_id:1}).toArray();
Run Code Online (Sandbox Code Playgroud)
然后根据接收的文档数量生成随机数字序列,然后使用随机数作为该数组的索引从数组中获取文档ID,然后最后再向mongodb请求获取具有随机选择的ID的文档.
正如你所看到的,它似乎有点太慢了,特别是,如果第一个查询返回的文章太多了:)
所以我认为可能有一些mongodb命令通过索引键根据它们在索引中的位置来获取文档.关键是我可以像这样创建覆盖复合索引:
db.articles.ensureIndex({topic: 1, _id:1});
Run Code Online (Sandbox Code Playgroud)
现在我的查询只需扫描索引中右_id的连续行.如果我可以通过那些'_ids'位置请求集合中的文档,那么我可以在一个请求中完成整个过程!就像是:
var cursor = db.articles.find({topic:3, $indexKeyPosition: {$in: myRandomSequence}});
Run Code Online (Sandbox Code Playgroud)
有谁知道这些功能?
鉴于没有数字索引,从Meteor集合中获取随机文档的最有效算法是什么?
(还有一个问题涉及使用该skip方法在MongoDB中这样做,但Meteor似乎并不支持这个问题).
我提出的低效方法是选择所有记录并迭代到一个随机数,但随着集合规模的增长,这显然变得昂贵和繁琐.
我想要来自mongoDB集合的单个随机文档.现在我的mongoDB集合包含超过10亿个集合.如何从该集合中获取单个随机文档?
我有一个带文件的mongo集合.每个文档中都有一个字段为0或1.我需要从数据库中随机抽取1000条记录,并将具有该字段的文档数量计为1.我需要对此进行1000次抽样.我该怎么做 ?
有很多方法可以从 mongodb 集合中选择随机文档(如本答案中所述)。评论指出,如果 mongodb 版本 >= 3.2,则$sample首选在聚合框架中使用。然而,在包含许多小文档的集合上,这似乎非常慢。
下面的代码使用mongoengine来模拟该问题并与“skip random”方法进行比较:
import timeit
from random import randint
import mongoengine as mdb
mdb.connect("test-agg")
class ACollection(mdb.Document):
name = mdb.StringField(unique=True)
meta = {'indexes': ['name']}
ACollection.drop_collection()
ACollection.objects.insert([ACollection(name="Document {}".format(n)) for n in range(50000)])
def agg():
doc = list(ACollection.objects.aggregate({"$sample": {'size': 1}}))[0]
print(doc['name'])
def skip_random():
n = ACollection.objects.count()
doc = ACollection.objects.skip(randint(1, n)).limit(1)[0]
print(doc['name'])
if __name__ == '__main__':
print("agg took {:2.2f}s".format(timeit.timeit(agg, number=1)))
print("skip_random took {:2.2f}s".format(timeit.timeit(skip_random, number=1)))
Run Code Online (Sandbox Code Playgroud)
结果是:
Document 44551
agg took 21.89s
Document 25800
skip_random took …Run Code Online (Sandbox Code Playgroud) 我正在基于任务队列构建应用程序:它为多个异步连接的客户端提供一系列任务。不同之处在于,必须按随机顺序执行任务。
我的问题是,我现在使用的算法在计算上非常昂贵,因为它依赖于许多大型查询和来自数据库的传输。我很想知道有一种便宜的方法可以达到相同的结果,但是我看不出解决方案。您能想到针对此问题的巧妙解决方案吗?
这是我现在正在使用的(计算上昂贵的)算法:
当客户查询新任务时...
客户完成任务后...
6a。记录结果并将任务标记为“完成”。
如果客户未能在一定期限内完成任务...
6b。将任务重新标记为“未完成”。
似乎我们可以通过用伪随机序列或哈希函数替换步骤1、2和3来做得更好。但是我不太清楚整个解决方案。有想法吗?
其他注意事项:
我知道MongoDB实际上还不支持随机记录选择,但我找到了几种解决方法。
但是,我想选择一个加权随机项目。这对 mySql来说相当容易,但我不确定使用 Mongo 的最佳方法。
我正在解决的问题是:我有一个收藏抽奖条目,根据用户分享/推广比赛的次数,他们会获得一个“额外条目”,以增加他们获胜的机会。我没有复制用户的条目,而是有一个字段来记录他们分享比赛的次数。我想用这个数字作为乘数来加权随机选择的“赢家”。
以下是我想到的几种方法:
我在这里有什么事情吗?对于我缺少的明显解决方案,还有其他建议吗?我将做一些实验,看看什么是有效的,但欢迎对我最初的想法提供任何反馈!!
性能需要“好”而不是“好”,因为这些比赛中没有一个可能会有数百万个条目(通常更像是 [数万] 万个),因此公平性/准确性比速度更重要。谢谢。