2015-11-19 69 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,同時指定一個字段的子集? –

相關問題