我想从一个巨大的集合(1亿条记录)中获得一个随机记录。
最快最有效的方法是什么?
数据已经在那里,没有字段可以生成随机数并获得随机行。
我想从一个巨大的集合(1亿条记录)中获得一个随机记录。
最快最有效的方法是什么?
数据已经在那里,没有字段可以生成随机数并获得随机行。
当前回答
对于我来说,我想以随机顺序获得相同的记录,所以我创建了一个用于排序的空数组,然后生成1到7之间的随机数(我有7个字段)。每次我得到一个不同的值,我分配一个不同的随机排序。 这是“外行”,但对我来说很管用。
//generate random number
const randomval = some random value;
//declare sort array and initialize to empty
const sort = [];
//write a conditional if else to get to decide which sort to use
if(randomval == 1)
{
sort.push(...['createdAt',1]);
}
else if(randomval == 2)
{
sort.push(...['_id',1]);
}
....
else if(randomval == n)
{
sort.push(...['n',1]);
}
其他回答
从MongoDB 3.2版本开始,你可以使用$sample聚合管道操作符从集合中随机获得N个文档:
// Get one random document from the mycoll collection.
db.mycoll.aggregate([{ $sample: { size: 1 } }])
如果你想从集合的筛选子集中选择随机文档,在管道中预先添加$match阶段:
// Get one random document matching {a: 10} from the mycoll collection.
db.mycoll.aggregate([
{ $match: { a: 10 } },
{ $sample: { size: 1 } }
])
正如注释中所指出的,当size大于1时,返回的文档样例中可能有重复项。
我对php的解决方案:
/**
* Get random docs from Mongo
* @param $collection
* @param $where
* @param $fields
* @param $limit
* @author happy-code
* @url happy-code.com
*/
private function _mongodb_get_random (MongoCollection $collection, $where = array(), $fields = array(), $limit = false) {
// Total docs
$count = $collection->find($where, $fields)->count();
if (!$limit) {
// Get all docs
$limit = $count;
}
$data = array();
for( $i = 0; $i < $limit; $i++ ) {
// Skip documents
$skip = rand(0, ($count-1) );
if ($skip !== 0) {
$doc = $collection->find($where, $fields)->skip($skip)->limit(1)->getNext();
} else {
$doc = $collection->find($where, $fields)->limit(1)->getNext();
}
if (is_array($doc)) {
// Catch document
$data[ $doc['_id']->{'$id'} ] = $doc;
// Ignore current document when making the next iteration
$where['_id']['$nin'][] = $doc['_id'];
}
// Every iteration catch document and decrease in the total number of document
$count--;
}
return $data;
}
为了获得确定数量的无重复的随机文档:
first get all ids get size of documents loop geting random index and skip duplicated number_of_docs=7 db.collection('preguntas').find({},{_id:1}).toArray(function(err, arr) { count=arr.length idsram=[] rans=[] while(number_of_docs!=0){ var R = Math.floor(Math.random() * count); if (rans.indexOf(R) > -1) { continue } else { ans.push(R) idsram.push(arr[R]._id) number_of_docs-- } } db.collection('preguntas').find({}).toArray(function(err1, doc1) { if (err1) { console.log(err1); return; } res.send(doc1) }); });
您可以选择一个随机时间戳,然后搜索随后创建的第一个对象。 它将只扫描单个文档,尽管它不一定会给您一个统一的分布。
var randRec = function() {
// replace with your collection
var coll = db.collection
// get unixtime of first and last record
var min = coll.find().sort({_id: 1}).limit(1)[0]._id.getTimestamp() - 0;
var max = coll.find().sort({_id: -1}).limit(1)[0]._id.getTimestamp() - 0;
// allow to pass additional query params
return function(query) {
if (typeof query === 'undefined') query = {}
var randTime = Math.round(Math.random() * (max - min)) + min;
var hexSeconds = Math.floor(randTime / 1000).toString(16);
var id = ObjectId(hexSeconds + "0000000000000000");
query._id = {$gte: id}
return coll.find(query).limit(1)
};
}();
您可以选择随机_id并返回相应的对象:
db.collection.count( function(err, count){
db.collection.distinct( "_id" , function( err, result) {
if (err)
res.send(err)
var randomId = result[Math.floor(Math.random() * (count-1))]
db.collection.findOne( { _id: randomId } , function( err, result) {
if (err)
res.send(err)
console.log(result)
})
})
})
在这里,你不需要花空间存储随机数字的集合。