【问题标题】:MongoDB and rmongodb. Get size of find instead of returning all resultsMongoDB 和 rmongodb。获取查找的大小而不是返回所有结果
【发布时间】: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() 两者都返回文档数。

【问题讨论】:

    标签: r mongodb rmongodb


    【解决方案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?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多