MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果

Posted

技术标签:

【中文标题】MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果【英文标题】:MongoDB and rmongodb. Get size of find instead of returning all results 【发布时间】:2015-11-19 16:53:35 【问题描述】:

我有一个包含超过 100k 个文档的 MongoDB 集合(这个数字将继续增长)。每个文档都有几个字段是单个值,大约 50 个字段是长度为 1000 的数组。我正在使用 rmongodb 分析 R 中的结果。

在 rmongodb 中,我使用 mongo.find.all() 将查询设置为要搜索的某些条件组合,并将字段设置为要返回的字段的子集。 mongo shell 中的等价物类似于:

db.collection.find(query1 : "value1", query2 : "value2",field1 : 1, field2 : 1, field3 : 1)

这将返回结果的 data.frame,我对其进行一些后处理并最终得到一个 data.table。

我想做的是为查询添加一些保护措施。如果查询范围很广,并且返回的字段是许多较大的数组字段,则结果 data.table 可能在几十 GB。这可能是预期的结果,但我想添加一些标志或错误检查,以免有人不小心尝试一次返回数百 GB。

我知道我可以计算与查询匹配的文档数(rmongodb 中的mongo.count,shell 中的db.collection.find(...,...).count())。我还可以获得平均文档大小 (db.collection.stats().avgObjSize)。

我不知道该怎么做,也不知道是否可能,是在实际返回查找之前获取查找的大小(以 MB 为单位,而不是数字)。由于我经常只返回字段的子集,因此 count 和 avgObjSize 并不能非常准确地估计结果 data.table 的大小。大小需要同时考虑查询和字段。

是否有类似db.collection.find(,).sizeOf() 的命令可以返回我的查找(查询、字段)的大小(以 MB 为单位)?我能看到的唯一选项是 count()size() 两者都返回文档数。

【问题讨论】:

【参考方案1】:

您可以手动遍历光标(就像在 mongo.cursor.to.list 中所做的那样)并反复检查结果对象的大小。像这样的:

LIMIT = 1024 * 1024 * 1024
res_size = 0
mongo.cursor.to.list_with_check <- function (cursor, 
                                             keep.ordering = TRUE, 
                                             limit = LIMIT) 
    # make environment to avoid extra copies
    e <- new.env(parent = emptyenv())
    i <- 1
    while (mongo.cursor.next(cursor) && res_size < limit) 
        val = mongo.bson.to.list(mongo.cursor.value(cursor))
        res_size = res_size + object.size(val)
        assign(x = as.character(i),
               value = val, envir = e)
        i <- i + 1
    
    # convert back to list
    res <- as.list(e)
    if (isTRUE(keep.ordering)) setNames(res[order(as.integer(names(res)))], NULL)
    else setNames(res, NULL)

之后,您可以通过data.table::rbindlist() 将其转换为data.table

【讨论】:

谢谢德米特里。我希望可以让 mongo 在不传输任何数据的情况下返回大小。我不想设置硬限制,但可能会出现类似“警告,返回的数据帧将是 16GB,您要继续吗?”的标记警告。我认为可行的方法是使用您上面的想法,但只返回一份文件。由于在我的项目中每个文档都将返回相同的大小,我可以结合单个文档的 mongo.count() 和 object.size 来获得预期的总大小,然后根据该计算进行设置。避免转移过多。 当然,如果您的记录大小大多相似,您可以使用mongo.count 乘以文档的平均大小。没有数据读取/传输就没有解决方案。 是的,我认为可能是这种情况,但我想我会先检查一下。如果有一个等效于mongo.countdb.collection.find(query).count() 的函数会返回查询/字段的大小,那就太好了。您使用mongo.cursor.to.list 一次返回一个的想法,结合mongo.count 似乎是最好的选择。感谢您的帮助!【参考方案2】:

您可以为这种情况下所需的灵活性编写脚本: (我假设你想返回最大 1GB)

    //limit 1GB
    var mbLimit = 1024*1024;
    //find number to show and round it to an int
    var numberShow = (mbLimit/db.restaurants.stats().avrObjSize) | 0;
    //limit the query
    db.restaurants.find(
       query1 : "value1", query2 : "value2",field1 : 1, field2 : 1, field3 : 1
        ).limit(numberShow)

【讨论】:

感谢您的回复。如果我返回所有字段,您的回答会很好。但是,我经常返回 50 个长数组字段中的 1 个,在这种情况下,我返回的平均文档大小约为 avgObjSize 的 1/50。或者我可能只返回一些单值字段而不返回更大的数组,在这种情况下,与 avgObjSize 相比,返回的对象非常小。有没有办法在指定字段子集的同时获取 avgObjSize?

以上是关于MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果的主要内容,如果未能解决你的问题,请参考以下文章

使用 rmongodb 和 plyr 将大型 MongoDB 集合传输到 R 中的 data.frame

更新 MongoDB 中的多个文档 (rmongodb)

rmongodb: $exists 给出空结果

使用 rmongodb 连接到 MongoDB 副本集

如何使用 rmongodb 将数据框插入 mongodb

使用 rmongodb 在 R 中运行高级 MongoDB 查询