1

我有一个包含超过 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。

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

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

有没有这样的命令db.collection.find({},{}).sizeOf()会返回我的查找(查询,字段)的 MB 大小?我能看到的唯一选项是count()两者size()都返回文档的数量。

4

2 回答 2

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.tablevia data.table::rbindlist()

于 2015-11-20T09:23:37.790 回答
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)
于 2015-11-19T17:46:23.793 回答