当前位置: 首页 > 知识库问答 >
问题:

MongoDB:如何在100个集合中找到10个随机文档?

蒙墨竹
2023-03-14

MongoDB是否能够在不进行多次查询的情况下资助大量随机文档?

e、 g.我在加载集合中的所有文档后在JS端实现,这很浪费-因此,我只想检查一下,是否可以通过一个db查询更好地实现这一点?

我在JS方面所走的道路:

  • 获取所有数据
  • 制作一个ID数组
  • 洗牌ID数组(随机顺序)
  • 将数组拼接到所需的文档数
  • 通过按ID选择它们来创建文档列表,我们在之前的两次操作后留下了这些ID,一个接一个地从整个集合中

两个主要缺点是我加载了所有数据,或者我进行了多次查询。

非常感谢任何建议

共有3个答案

楮乐邦
2023-03-14

这是我最后想到的:

var numberOfItems = 10;


// GET LIST OF ALL ID's
SchemaNameHere.find({}, { '_id': 1 }, function(err, data) {

    if (err) res.send(err);

    // shuffle array, as per here  https://github.com/coolaj86/knuth-shuffle
    var arr = shuffle(data.slice(0));

    // get only the first numberOfItems of the shuffled array
    arr.splice(numberOfItems, arr.length - numberOfItems);

    // new array to store all items
    var return_arr = [];

    // use async each, as per here http://justinklemm.com/node-js-async-tutorial/
    async.each(arr, function(item, callback) {

        // get items 1 by 1 and add to the return_arr
        SchemaNameHere.findById(item._id, function(err, data) {

            if (err) res.send(err);
            return_arr.push(data);

            // go to the next one item, or to the next function if done
            callback();

        });

    }, function(err) {

        // run this when looped through all items in arr
        res.json(return_arr);

    });

});
公冶弘壮
2023-03-14

从3.2开始,有一种更简单的方法可以从集合中获取随机文档样本:

$3.2版中的新示例。

从其输入中随机选择指定数量的文档。

$example阶段具有以下语法:

{$样本:{大小:

来源:MongoDB文档

在这种情况下:

db.products.aggregate([{$sample: {size: 10}}]);

毛胜
2023-03-14

这在很久以前就得到了回答,从那时起,MongoDB有了很大的发展。

如另一个答案所示,自3.2版以来,MongoDB现在支持在聚合框架内进行采样:

您可以这样做:

db.products.aggregate([{$sample: {size: 5}}]); // You want to get 5 docs

或:

db.products.aggregate([
  {$match: {category:"Electronic Devices"}}, // filter the results
  {$sample: {size: 5}} // You want to get 5 docs
]);

但是,对于$sample运算符有一些警告:

(截至2017年11月6日,最新版本为3.4)=

  • $sample是管道的第一阶段

如果不满足上述任何条件,$sample执行收集扫描,然后进行随机排序,以选择N个文档。

就像上一个例子中的$match

旧答案

你可以一直跑步:

db.products.find({category:"Electronic Devices"}).skip(Math.random()*YOUR_COLLECTION_SIZE)

但是顺序不会是随机的,你需要两个查询(一个计数来获得YOUR_COLLECTION_SIZE)或估计它有多大(大约100条记录,大约1000条,大约10000条...)

您还可以向所有带有随机数的文档添加一个字段,并按该数字进行查询。这里的缺点是每次运行相同的查询都会得到相同的结果。为了解决这个问题,您可以始终使用限制和跳过甚至排序。您也可以在每次获取记录时更新这些随机数(意味着更多查询)。

--我不知道您是在使用Mongoose、Mondoid还是直接使用Mongo驱动程序来实现任何特定的语言,所以我将写下所有关于MongoShell的内容。

因此,假设您的产品记录如下所示:

{
 _id: ObjectId("..."),
 name: "Awesome Product",
 category: "Electronic Devices",
}

我建议使用:

{
 _id: ObjectId("..."),
 name: "Awesome Product",
 category: "Electronic Devices",
 _random_sample: Math.random()
}

然后你可以做:

db.products.find({category:"Electronic Devices",_random_sample:{$gte:Math.random()}})

然后,您可以定期运行,以便定期更新文档的\u random\u样本字段:

var your_query = {} //it would impact in your performance if there are a lot of records
your_query = {category: "Electronic Devices"} //Update 
//upsert = false, multi = true
db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)

或者只是每当您检索一些记录时,您可以更新所有记录或仅更新少数记录(取决于您检索了多少记录)

for(var i = 0; i < records.length; i++){
   var query = {_id: records[i]._id};
   //upsert = false, multi = false
   db.products.update(query,{$set:{_random_sample::Math.random()}},false,false);
}

编辑

请注意

db.products.update(your_query,{$set:{_random_sample::Math.random()}},false,true)

不会很好地工作,因为它会用相同的随机数更新与您的查询匹配的每个产品。最后一种方法效果更好(在检索某些文档时更新它们)

 类似资料:
  • 在上面的屏幕截图中,您可以看到我从mongo数据库中的测试集合中打开了一个名为(1)ObjectId(572b…ec7a)的文档。(测试集合中充满了这样的文档)在屏幕截图底部附近,您可以看到一个名为Name的字段,该字段的类型为string,值为EditMessagesSettings。我想查询tests集合并返回任何包含特定名称的文档(如本例中的EditMessagesSettings)。我该怎

  • 我有一个问题,但在我看来,我看到的所有解决方案都在解决一个比我更复杂的问题。 我对MongoDB比较陌生,但我一直在将它与Apache Neach一起使用来存储抓取的文档。由于我分阶段抓取,并以不同的方式评估每个抓取的结果,以获取统计数据,因此我一直将结果存储在不同的集合中。 我所要做的就是把这些收藏放在一起成为一个大的收藏,这样我就可以翻译和分类。所有字段都是相同的,因此我不需要添加任何新字段。

  • 问题内容: 对于我的应用程序而言,至关重要的是能够从Firebase的集合中随机选择多个文档。 由于Firebase(我知道)没有内置本机函数来实现执行此操作的查询,因此我的第一个想法是使用查询游标选择随机的起始索引和终止索引,前提是我拥有​​其中的文档数集合。 这种方法行之有效,但只能以有限的方式进行,因为每次每次文档都会与其相邻文档一起依次送达。但是,如果我能够通过其父集合中的索引选择一个文档

  • 我在Mongo DB Atlas中收集了一个用户名称。 它还在继续。 在节点中可以使用什么查询。js和mongoose找到集合中的最后一个元素了吗?当集合不断动态增加时,如何获取集合最后一个元素的id?

  • 这里是我尝试的代码,我成功地获得了所有集合的名称,但当我搜索特定的字段时,它不起作用,也没有给我任何错误。 该代码没有错误,也没有警告。

  • 我知道有一种方法可以实现db。收集getIndexes(),它将列出为集合定义的所有索引。有没有办法将这些索引定义复制并创建到另一个集合? 有很多,我不想一个接一个地做。 关于重复的问题评论:我不希望复制收藏。我希望以可以应用于另一个集合的格式导出索引。