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

MongoDB and rmongodb. Get size of find instead of returning all results

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

在rmongodb中,我使用mongo.find.all(),查询设置为要搜索的条件的某种组合,而字段设置为要返回的字段的子集。 mongo shell中的等效内容如下:

1
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()这样的命令可以返回我的find(query,fields)的大小(以MB为单位)?我可以看到的唯一选项是count()size(),它们都返回文档的数量。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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


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

1
2
3
4
5
6
7
8
    //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)