MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果
Posted
技术标签:
【中文标题】MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果【英文标题】:MongoDB and rmongodb. Get size of find instead of returning all results 【发布时间】: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()
两者都返回文档数。
【问题讨论】:
【参考方案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.count
或db.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?以上是关于MongoDB 和 rmongodb。获取查找的大小而不是返回所有结果的主要内容,如果未能解决你的问题,请参考以下文章