簡體   English   中英

來自 Mongoose 集合的隨機文檔

[英]Random document from a collection in Mongoose

我想創建一個Schema.statics.random函數,從集合中獲取一個隨機元素。 我知道有一個本地 MongoDB 驅動程序的示例,但我無法在 Mongoose 中使用它。

我在 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

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

如果您不想將“類似測試”的代碼添加到您的架構中,則可以使用 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 

  });

});

一個更短但可能更高效的解決方案
(我們不會遍歷集合一次來計數和第二次跳過元素,但貓鼬可能會在幕后這樣做):

使用聚合和 $sample

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

您可以使用聚合:

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

我已經為 mongoose 實現了一個插件,它使用 2dsphere 索引在兩個隨機生成的坐標上使用 $near 查詢以非常有效的方式執行此操作。 在這里查看: https : //github.com/matomesc/mongoose-random

對於在 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;
};

現在推薦使用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
}
// 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(),但為了提高性能,建議使用 EstimatedDocumentCount()。

我更喜歡這種方法,因為它得到的是一個文檔而不是一個數組。

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

給出 3 個隨機文檔的命令:

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

快遞專線獲取4個隨機文件。 我認為它適用於最新版本的 mongo。

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

請參閱此鏈接以獲取更多信息

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM