[英]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.我更喜欢这种方法,因为它得到的是一个文档而不是一个数组。
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}}])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.