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

时间:2015-11-19 16:53:35

标签: r mongodb rmongodb

我有一个带有> 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(),这两个选项都会返回文档数量。

2 个答案:

答案 0 :(得分: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将其转换为data.table::rbindlist()

答案 1 :(得分:0)

您可以编写脚本以满足此情况下所需的灵活性: (我假设你想要最多返回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)