【问题标题】:Possible to retrieve multiple random, non-sequential documents from MongoDB?可以从 MongoDB 中检索多个随机的、非顺序的文档吗?
【发布时间】:2015-02-05 13:35:44
【问题描述】:

我想从 MongoDB 数据库中检索一组随机文档。到目前为止,经过大量谷歌搜索,我只看到了检索一个随机文档或一组文档的方法,这些文档从随机跳过位置开始,但文档仍然是连续的。

我尝试过 mongoose-simple-random,但不幸的是它没有检索到“真正的”随机集。它的作用是跳到一个随机位置,然后从该位置检索 n 个文档。

相反,我想像 MySQL 一样使用 一个查询(或最少数量的查询)检索一个随机集,并且我需要这个列表每次都是随机的。我需要它是高效的——相对于 MySQL 的这种查询。我想在 MongoDB 中重现以下内容:

SELECT * FROM products ORDER BY rand() LIMIT 50;

这可能吗?我正在使用 Mongoose,但任何适配器的示例——甚至是直接的 MongoDB 查询——都很酷。

我见过一种方法,可以为每个文档添加一个字段,为每个字段生成一个随机值,并使用{rand: {$gte:rand()}} 每个我们想要随机化的查询。但是,我担心两个查询理论上会返回相同的集合。

【问题讨论】:

  • 如果您可以“检索一个随机文档”,那么您可以通过重复检索多个,不是吗?
  • 我认为这会效率低下——我需要它与 MySQL rand() 排序查询相提并论。

标签: mongodb random mongoose


【解决方案1】:

你可以做两个请求,但是以一种有效的方式:

  1. 您的第一个请求只是获取您收藏的文档的所有“_id”列表。请务必使用 mongo 投影 db.products.find({}, { '_id' : 1 })
  2. 您有一个“_id”列表,只需从列表中随机选择 N 个即可。
  3. 使用 $in 运算符进行第二次查询。

特别重要的是,您的第一个查询完全由索引支持(因为它是“_id”)。该索引可能完全在内存中(否则您可能会遇到性能问题)。因此,在运行第一个查询时只读取索引,而且速度非常快。

虽然第二个查询意味着读取实际文档,但索引会有很大帮助。

如果你能做到这一点,你应该试试。

【讨论】:

  • 如果我的收藏中有 500,000 个文档,这仍然有效吗?
  • @ChadJohnson 不,甚至不接近,您需要一个单独的字段:stackoverflow.com/questions/2824157/random-record-from-mongodb 尝试查看除第一个答案之外的任何内容
  • @Chad Johnson:了解它的最佳方式可能是试穿您的收藏。对于第一个请求,为了实现您的目标(真正随机的文档),您不应该使用限制。但是,如果您只是想测试第一个请求是否意味着您的生产系统上的内容过于密集,您可以尝试限制为 1000,然后是 5000、25000... 直到达到集合中的文档数量并确认一切正确。
  • @Sammaye :您能否链接到具体的答案,根据您的说法,这项工作是挑选 N(例如 50 个)随机文档的最佳方式吗?
  • stackoverflow.com/a/5517206/383478 在这种特定情况下进行一些更改会很好地工作,直接索引查询只提取需要的内容
【解决方案2】:

我不认为 MySQL ORDER BY rand() 效率特别高——据我了解,它本质上是为每一行分配一个随机数,然后在这个随机数列上对表进行排序并返回前 N 个结果。

如果您愿意接受插入集合的一些开销,您可以将问题减少到在一个范围内生成 N 个随机整数。为每个文档添加一个计数器字段:每个文档将按顺序分配一个唯一的正整数。什么文档得到什么编号并不重要,只要分配是唯一的并且数字是连续的,并且您要么不删除文档,要么使计数器文档方案复杂化以处理漏洞。您可以通过两步插入来做到这一点。在单独的counter 集合中,保留一个文档,其中包含第一个未用于计数器的编号。当插入发生时,首先findAndModify 计数器文档以检索下一个计数器值并自动递增计数器值。然后插入带有计数器值的新文档。要找到 N 个随机值,请找到最大计数器值,然后在最大计数器定义的范围内生成 N 个不同的随机数,然后使用$in 检索文档。大多数语言都应该有随机库来处理在一个范围内生成 N 个随机整数。

【讨论】:

  • “只要分配是唯一的并且数字是连续的”->只要文档永远不会被删除,我也会添加。
  • 如果我没记错的话,rand() 不是真的从桌子上的 AI 钥匙中挑选的吗?
  • @dotpush - 很好的观点。它确实需要不删除文档。我已经编辑了答案。您可以使编号方案更复杂以允许删除。我认为,对于许多用例而言,仅进行单次随机抽取可能比围绕抽取样本构建集合的使用更容易。
猜你喜欢
  • 1970-01-01
  • 2017-07-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 2016-03-02
  • 1970-01-01
相关资源
最近更新 更多