MongoDB的随机记录

MongoDB的随机记录,mongodb,random,mongodb-query,Mongodb,Random,Mongodb Query,我希望从一个巨大的(1亿条记录)mongodb中获得一条随机记录 最快和最有效的方法是什么?数据已经存在,并且没有可以生成随机数并获得随机行的字段 有什么建议吗?对所有记录进行计数,生成一个介于0和计数之间的随机数,然后执行以下操作: db.yourCollection.find().limit(-1).skip(yourRandomNumber).next() 如果没有数据可供检索,那就很难了。什么是_id字段?它们是mongodb对象id吗?如果是,则可以获得最高和最低值: lowest

我希望从一个巨大的(1亿条记录)
mongodb
中获得一条随机记录

最快和最有效的方法是什么?数据已经存在,并且没有可以生成随机数并获得随机行的字段


有什么建议吗?

对所有记录进行计数,生成一个介于0和计数之间的随机数,然后执行以下操作:

db.yourCollection.find().limit(-1).skip(yourRandomNumber).next()

如果没有数据可供检索,那就很难了。什么是_id字段?它们是mongodb对象id吗?如果是,则可以获得最高和最低值:

lowest = db.coll.find().sort({_id:1}).limit(1).next()._id;
highest = db.coll.find().sort({_id:-1}).limit(1).next()._id;
然后,如果您假设id是均匀分布的(但它们不是,但至少这是一个开始):


我建议给每个对象添加一个随机int字段。然后你就可以做一个

findOne({random_field: {$gte: rand()}}) 

随机选取一个文档。只需确保确保索引({random_field:1})

高效可靠的工作原理如下:

向每个文档添加一个名为“random”的字段,并为其指定一个随机值,为该随机字段添加索引,然后按如下步骤进行操作:

假设我们有一个名为“链接”的web链接集合,我们希望从中获得一个随机链接:

link = db.links.find().sort({random: 1}).limit(1)[0]
为确保同一链接不会再次弹出,请使用新的随机数更新其随机场:

db.links.update({random: Math.random()}, link)
MongoDB 3.2的更新 3.2引入聚合管道

把它付诸实践也有好处

对于旧版本(以前的答案) 这实际上是一个功能请求:但它是在“不会修复”下提交的

食谱中有一个很好的方法可以从集合中随机选择一个文档:

要解释配方,请将随机数指定给文档:

db.docs.save( { key : 1, ..., random : Math.random() } )
const samples = (
  await Sample.aggregate([
    { $match: {} },
    { $sample: { size: 27 } },
    { $project: { _id: 1 } },
  ]).exec()
).map(v => v._id);

const mongooseSamples = await Sample.find({ _id: { $in: samples } });

console.log(mongooseSamples); //an Array of mongoose documents
然后选择一个随机文档:

rand = Math.random()
result = db.docs.findOne( { key : 2, random : { $gte : rand } } )
if ( result == null ) {
  result = db.docs.findOne( { key : 2, random : { $lte : rand } } )
}
同时使用
$gte
$lte
进行查询是查找随机数最接近
rand
的文档所必需的

当然,你需要在随机场上建立索引:

db.docs.ensureIndex( { key : 1, random :1 } )

如果您已经在查询某个索引,只需删除它,将其附加到
random:1
,然后再次添加它。

我建议使用map/reduce,其中使用map函数仅在随机值高于给定概率时发射

function mapf() {
    if(Math.random() <= probability) {
    emit(1, this);
    }
}

function reducef(key,values) {
    return {"documents": values};
}

res = db.questions.mapReduce(mapf, reducef, {"out": {"inline": 1}, "scope": { "probability": 0.5}});
printjson(res.results);
函数mapf(){

如果(Math.random(),您还可以使用MongoDB的地理空间索引功能来选择与随机数“最近”的文档

首先,对集合启用地理空间索引:

db.docs.ensureIndex( { random_point: '2d' } )
要创建一组在X轴上具有随机点的文档,请执行以下操作:

for ( i = 0; i < 10; ++i ) {
    db.docs.insert( { key: i, random_point: [Math.random(), 0] } );
}
或者,您可以检索离随机点最近的多个文档:

db.docs.find( { random_point : { $near : [Math.random(), 0] } } ).limit( 4 )

这只需要一个查询,不需要空检查,而且代码干净、简单、灵活。您甚至可以使用地质点的Y轴向查询添加第二个随机维度。

如果您有一个简单的id键,您可以将所有id存储在一个数组中,然后选择一个随机id(Ruby answer):


当我面对类似的解决方案时,我回过头来发现业务请求实际上是为了创建某种形式的库存轮换。在这种情况下,有更好的选择,它们的答案来自Solr等搜索引擎,而不是MongoDB等数据存储

简而言之,要求“智能旋转”内容,我们应该做的不是在所有文档中使用随机数,而是包含一个个人q分数修饰符。为了自己实现这一点,假设用户数量较少,您可以为每个用户存储一个文档,该文档包含productId、印象数、点击次数、最后一次看到的日期,以及任何其他影响业务的因素ds对于计算q分数修饰符是有意义的。检索要显示的集合时,通常您从数据存储中请求的文档比最终用户请求的文档多,然后应用q分数修饰符,获取最终用户请求的记录数,然后随机化结果页,这是一个很小的集合,因此只需按e应用层(内存中)

如果用户范围太大,则可以将用户分类为行为组,并按行为组而不是用户索引

如果产品的范围足够小,您可以为每个用户创建一个索引


我发现这种技术效率更高,但更重要的是,在创建相关的、有价值的软件解决方案使用体验方面更有效。

如果您使用mongoid,文档到对象包装器,您可以在 Ruby。(假设您的模型是用户)

在我的.irbrc中,我有

def rando klass
    klass.all.to_a[rand(klass.count)]
end
所以在rails控制台中,我可以做,例如

rando User
rando Article

从任何集合中随机获取文档。

没有一种解决方案对我来说效果很好。特别是当有很多间隙且集合很小时。 这对我来说非常有效(在php中):


使用Map/Reduce,您当然可以获得一个随机记录,但根据最终使用的过滤集合的大小,不一定效率很高

我已经用50000个文档测试了这种方法(过滤器将其减少到大约30000个),它在一个带有16GB ram和SATA3 HDD的Intel i3上执行大约400毫秒

db.toc_content.mapReduce(
    /* map function */
    function() { emit( 1, this._id ); },

    /* reduce function */
    function(k,v) {
        var r = Math.floor((Math.random()*v.length));
        return v[r];
    },

    /* options */
    {
        out: { inline: 1 },
        /* Filter the collection to "A"ctive documents */
        query: { status: "A" }
    }
);
Map函数只是创建一个与查询匹配的所有文档的id数组。在我的例子中,我用50000个可能的文档中的大约30000个进行了测试

Reduce函数简单地选择一个介于0和数组中的项数(-1)之间的随机整数,然后从数组中返回\u id

400ms听起来很长时间,事实上,如果您有五千万条记录而不是五万条,这可能会增加开销,使其在多用户情况下变得不可用

MongoDB在核心中包含此功能还有一个悬而未决的问题

如果这种“随机”选择是建立在索引查找中的,而不是将ID收集到一个数组中然后选择一个,这将非常有帮助。(去投票吧!)

下面的方法是
User.all.to_a[rand(User.count)]
def rando klass
    klass.all.to_a[rand(klass.count)]
end
rando User
rando Article
$count = $collection->count($search);
$skip = mt_rand(0, $count - 1);
$result = $collection->find($search)->skip($skip)->limit(1)->getNext();
db.toc_content.mapReduce(
    /* map function */
    function() { emit( 1, this._id ); },

    /* reduce function */
    function(k,v) {
        var r = Math.floor((Math.random()*v.length));
        return v[r];
    },

    /* options */
    {
        out: { inline: 1 },
        /* Filter the collection to "A"ctive documents */
        query: { status: "A" }
    }
);
import random

def get_random_doc():
    count = collection.count()
    return collection.find()[random.randrange(count)]
 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)
            })
        })
    })
// Get one random document matching {a: 10} from the mycoll collection.
db.mycoll.aggregate([
    { $match: { a: 10 } },
    { $sample: { size: 1 } }
])
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)
            });
        });
db.users.aggregate(
   [ { $sample: { size: 3 } } ]
)
collection.aggregate([{'$sample': {'size': sample_size }}])
    $randomNumbers = [];
    for($i = 0; $i < 10; $i++){
        $randomNumbers[] = rand(0,1000);
    }
    $aggregate[] = [
        '$addFields' => [
            'random_sort' => [ '$arrayElemAt' => [ $randomNumbers, [ '$mod' => [ '$my_numeric_mysql_id', 10 ] ] ] ],
        ],
    ];
    $aggregate[] = [
        '$sort' => [
            'random_sort' => 1
        ]
    ];
/*
Sample model should be init first
const Sample = mongoose …
*/

const samples = await Sample.aggregate([
  { $match: {} },
  { $sample: { size: 33 } },
]).exec();
console.log(samples); //a lean Array
const samples = (
  await Sample.aggregate([
    { $match: {} },
    { $sample: { size: 27 } },
    { $project: { _id: 1 } },
  ]).exec()
).map(v => v._id);

const mongooseSamples = await Sample.find({ _id: { $in: samples } });

console.log(mongooseSamples); //an Array of mongoose documents