2015-11-19 24 views
0

我有一个MongoDB收集与> 100K文件(这个数字将继续增长)。每个文档有几个字段是单个值,大约50个字段都是长度为1000的数组。我使用rmongodb分析R中的结果。MongoDB和rmongodb。获取大小的查找,而不是返回所有结果

在rmongodb中,我使用的是mongo.find.all(),查询设置为搜索条件的某种组合,字段设置为要返回的字段子集。在蒙戈外壳等效会是这样的:

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

这返回的结果,这是我做一些后期处理上,并用data.table最终的data.frame。

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

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

我不知道该怎么做,也不知道是否可能,是在find实际返回之前获得find的大小(以MB为单位,而不是number)。由于我经常只返回字段的一个子集,因此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

+0

谢谢德米特里。我希望能够让mongo在不传输任何数据的情况下返回大小。我不想设置硬性限制,但可能会出现一条警告标志,警告:返回的数据帧将为16GB,是否要继续? 我认为可以工作的是使用你的想法,但只返回一个文档。由于在我的项目中每个文档都会返回相同的大小,因此我可以合并单个文档的mongo.count()和object.size以获得预期的总大小,然后根据该计算获取设置。它避免了转移太多。 –

+0

当然,如果您的记录大小基本相似,您可以使用'mongo.count'乘以文档的平均大小。没有数据读取/传输没有解决方案。 –

+0

是的,我认为可能是这种情况,但认为我会先检查。如果存在与返回查询/字段大小的'mongo.count'或'db.collection.find(query).count()'相当的话会更好。你一次使用'mongo.cursor.to.list'返回一个想法,加上一个'mongo.count'似乎是最好的选择。谢谢你的帮助! –

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) 
+0

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

相关问题