简体   繁体   English

来自 Mongoose 集合的随机文档

[英]Random document from a collection in Mongoose

I want to create a Schema.statics.random function that gets me a random element from the collection.我想创建一个Schema.statics.random函数,从集合中获取一个随机元素。 I know there is an example for the native MongoDB driver, but I can't get it working in Mongoose.我知道有一个本地 MongoDB 驱动程序的示例,但我无法在 Mongoose 中使用它。

I found this Mongoose Schema static function in a GitHub Gist, which should achieve what you are after.我在 GitHub Gist 中找到了这个 Mongoose Schema 静态函数,它应该可以实现您的目标。 It counts number of documents in the collection and then returns one document after skipping a random amount.它计算集合中的文档数,然后在跳过随机数量后返回一个文档。

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));
};

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

NB I modified the code a bit to make it more readable.注意我稍微修改了代码以使其更具可读性。

If you are not wanting to add "test like" code into your schema, this uses Mongoose queries.如果您不想将“类似测试”的代码添加到您的架构中,则可以使用 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 

  });

});

A shorter and maybe more performant solution一个更短但可能更高效的解决方案
(we don't iterate through the collection once to count and a second time to skip elements, but mongoose might do that behind the scenes): (我们不会遍历集合一次来计数和第二次跳过元素,但猫鼬可能会在幕后这样做):

Use aggregate and $sample :使用聚合和 $sample

Model.aggregate([{ $sample: { size: 1 } }])

You can use aggregate:您可以使用聚合:

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

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

User.findRandom({gender: "male"}, {}, {limit: 10}, function(err, results) { 
    console.log(results); // 10 elements
});

I've implemented a plugin for mongoose that does this in a very efficient way using a $near query on two randomly generated coordinates using a 2dsphere index.我已经为 mongoose 实现了一个插件,它使用 2dsphere 索引在两个随机生成的坐标上使用 $near 查询以非常有效的方式执行此操作。 Check it out here: https://github.com/matomesc/mongoose-random .在这里查看: https : //github.com/matomesc/mongoose-random

For people looking at this in times of async/await, promises etc.:对于在 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;
};

Nowadays Model.estimatedDocumentCount() is recommended.现在推荐使用Model.estimatedDocumentCount() For the Model called Item an outline of a function would be:对于名为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
}
// 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);
    });
});

You can also use countDocuments(), but estimatedDocumentCount() is recommended for performance.您也可以使用 countDocuments(),但为了提高性能,建议使用 EstimatedDocumentCount()。

I prefer this method due to getting one document instead of an array.我更喜欢这种方法,因为它得到的是一个文档而不是一个数组。

  1. Get the total number of documents in collection.获取集合中的文档总数。
  2. Define a random number between 1 and the total number of documents.定义一个介于 1 和文档总数之间的随机数。
  3. Get a document and skip that random number.获取文档并跳过该随机数。
const total = await model.countDocuments();
const skip = Math.floor(Math.random() * total) + 1;
const randomDoc = await model.findOne({}).skip(skip).exec();

command which gives 3 random documents:给出 3 个随机文档的命令:

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

express line to get 4 random documents.快递专线获取4个随机文件。 i think it works in the latest versions of mongo.我认为它适用于最新版本的 mongo。

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

see this link for further info请参阅此链接以获取更多信息

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何更新文档以在 mongoose 中嵌入来自不同集合的现有文档 - How to update a document to embed an existing document from a different collection in mongoose 使用mongoose从mongodb集合中的文档数组中删除对象 - delete object from document array in mongodb collection using mongoose 猫鼬参考集合或嵌套文档2级深 - Mongoose reference collection or nested document 2 level deep 使用 ZCCADCDEDB567ABAE643E15DCF0974E503Z Model 检查文档是否存在于集合中 - Check if document exists in collection with Mongoose Model 如何从MongoDb集合中获取随机文档,然后在HTML中显示随机选择的文档的每个字段? - How can I get a random document from a MongoDb collection, and then display each of the fields of that randomly selected document in HTML? 有没有办法通过一些任意的排序标准从猫鼬集合中获取第n个文档? - Is there a way to get the n-th document from a mongoose collection by some arbitrary sorting criteria? 将一个新字段添加到集合的所有文档中,将文档字段中的值添加到 MongoDB (Mongoose) 中,记录为 300K+ - Add a new field to all documents of a collection with the value from the document field into MongoDB (Mongoose) with records of 300K+ mongoose 从另一个文档向一个文档添加一个字段 - mongoose add a field to a document from another document Mongoose - Model.deleteOne()正在删除整个集合而不是单个文档 - Mongoose - Model.deleteOne() is deleting the entire collection instead of a single document 使用Mongoose在所有现有集合中查找参考文档 - Finding a referenced document in all the existing collection using Mongoose
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM