27

我想创建一个Schema.statics.random从集合中获取随机元素的函数。我知道本地 MongoDB 驱动程序有一个示例,但我无法让它在 Mongoose 中工作。

4

10 回答 10

40

我在 GitHub Gist 中找到了这个 Mongoose Schema 静态函数,它应该可以实现你所追求的。它计算集合中的文档数,然后在跳过随机数量后返回一个文档。

QuoteSchema.statics.random = function(callback) {
  this.count(function(err, count) {
    if (err) {
      return callback(err);
    }
    var rand = Math.floor(Math.random() * count);
    this.findOne().skip(rand).exec(callback);
  }.bind(this));
};

来源:https ://gist.github.com/3453567

注意我稍微修改了代码以使其更具可读性。

于 2013-02-01T11:05:08.017 回答
22

如果您不想在架构中添加“类似测试”的代码,则使用 Mongoose 查询。

Model.count().exec(function(err, count){

  var random = Math.floor(Math.random() * count);

  Model.findOne().skip(random).exec(
    function (err, result) {

      // result is random 

  });

});
于 2015-02-04T20:59:31.133 回答
12

一个更短且可能更高效
的解决方案(我们不会遍历集合一次来计数,第二次遍历元素来跳过元素,但 mongoose 可能会在幕后这样做):

使用聚合和 $sample

Model.aggregate([{ $sample: { size: 1 } }])
于 2019-07-10T13:55:53.120 回答
11

您可以使用聚合:

User.aggregate([
    {$match: {gender: "male"}},
    {$sample: {size: 10}}
], function(err, docs) {
    console.log(docs);
});

或者你可以使用 npm 包https://www.npmjs.com/package/mongoose-simple-random

User.findRandom({gender: "male"}, {}, {limit: 10}, function(err, results) { 
    console.log(results); // 10 elements
});
于 2019-07-31T10:31:57.747 回答
6

我已经为猫鼬实现了一个插件,它以非常有效的方式使用 $near 查询使用 2dsphere 索引对两个随机生成的坐标进行查询。在这里查看:https ://github.com/matomesc/mongoose-random 。

于 2013-07-03T20:50:49.790 回答
3

对于在 async/await、promise 等时查看此内容的人:

MySchema.statics.random = async function() {
  const count = await this.count();
  const rand = Math.floor(Math.random() * count);
  const randomDoc = await this.findOne().skip(rand);
  return randomDoc;
};
于 2018-04-10T21:21:23.317 回答
1

现在推荐使用Model.estimatedDocumentCount()。对于称为Item函数大纲的模型将是:

const Item = require('../your/path/to/Model/Item')

async function getRandomItem() {
   const numItems = await Item.estimatedDocumentCount()
   const rand = Math.floor(Math.random() * numItems)
   const randomItem = await Item.findOne().skip(rand)
   return randomItem
}
于 2021-02-03T09:58:15.633 回答
0
// Getting estimated document count.
yourModel.estimatedDocumentCount().then((count) => {
  //Random number between 0 and count.
  const rand = Math.floor(Math.random() * count);

  // Finding ONE random document.
  yourModel
    .findOne()
    .skip(rand)
    .then((randomDocument) => {
      console.log(randomDocument);
    });
});

您也可以使用 countDocuments(),但建议使用 estimateDocumentCount() 来提高性能。

由于获取一个文档而不是数组,我更喜欢这种方法。

于 2021-02-05T00:36:18.083 回答
0
  1. 获取集合中的文档总数。
  2. 定义一个介于 1 和文档总数之间的随机数。
  3. 获取文档并跳过该随机数。
const total = await model.countDocuments();
const skip = Math.floor(Math.random() * total) + 1;
const randomDoc = await model.findOne({}).skip(skip).exec();
于 2021-02-15T19:03:17.007 回答
0

给出 3 个随机文档的命令:

db.collection.aggregate([{$sample:{limit: 3}}])

快递线随机获取4份文件。我认为它适用于最新版本的 mongo。

db.aggregate([{$sample:{limit: 4}}])

请参阅此链接以获取更多信息

于 2021-07-05T20:16:32.700 回答