2015-05-04 71 views
2

我剛剛熟悉Mongodb,這就是爲什麼我做了一些愚蠢的事情。我的每個數據集的條目都包含一個時間戳(他們是Tweets)。我沒有在插入之前將時間戳從字符串轉換爲實際日期格式,而是將其簡單插入爲字符串。Mongodb緩慢更新循環

現在,我的數據集變得非常龐大(超過3百萬條推文),我想開始排序/排列我的條目。由於我的時間戳仍然是一個字符串(「Wed Apr 29 09:52:22 +0000 2015」),我想將其轉換爲日期格式。

我發現這個答案下面的代碼: How do I convert a property in MongoDB from text to date type?

> var cursor = db.ClockTime.find() 
> while (cursor.hasNext()) { 
... var doc = cursor.next(); 
... db.ClockTime.update({_id : doc._id}, {$set : {ClockInTime : new Date(doc.ClockInTime)}}) 
... } 

而且它的偉大工程。然而,這是非常緩慢的。根據MongoHub應用程序,它每秒只處理4個查詢。使用300萬推文的數據集,這將需要大約8.6天的時間進行轉換。我真的希望有一種方法可以加快速度,因爲我的截止日期是8天:P

有什麼想法?

+2

看看這個[文章](https://midnightcodr.github.io/2014/11/22/How-to-convert-20-million-datetime-strings-to-ISODate-in-less-比-30分鐘/) – Yogesh

+0

這似乎很有前途,謝謝! – Diederik

回答

5

默認情況下,更新阻塞,直到數據庫發回確認成功執行更新爲止。當您在本地工作站上使用mongo shell並連接到遠程數據庫時,這至少需要ping到數據庫。

如果允許,可以通過SSH連接到數據庫服務器(副本集的主服務器)並在其中運行腳本。這將網絡延遲減少到幾乎爲零。當你有一個集羣時,結果可能仍然是一個改進,但並不是那麼多,因爲你需要登錄到mongos服務器,它仍然需要等待來自其更新路由的副本集的確認, 。

另一種選擇是執行更新,不寫入關注。程序執行將立即繼續,這將大大提高速度。但請記住,這種方式會忽略任何錯誤。

db.ClockTime.update(
    {_id : doc._id}, 
    {$set : {ClockInTime : new Date(doc.ClockInTime)}}, 
    {writeConcern: {w: 0}} 
) 

這將是更快的第三種選擇是使用mongoexport得到JSON格式的所有收藏的文件導出,與當地的腳本轉換它,然後用mongoimport重新導入的轉換數據。缺點是如果在導出和導入之間沒有很短的停機時間,您將無法做到這一點,因爲它們之間的任何數據都將丟失。

+0

謝謝你這個詳細的答案!事實上,登錄到SSH服務器的速度相當快,解決了問題,沒有數據丟失,因爲我不必導出/導入數據庫。 – Diederik

5

另一種選擇是使用批量操作,這是非常快的,尤其是the unordered variant,因爲它們可以並行應用。

var bulk = db.ClockTime.initializeUnorderedBulkOp() 
var myDocs = db.ClockTime.find() 

var ops = 0 

myDocs.forEach(

    function(myDoc) { 

    bulk.find(
     {_id:myDoc._id} 
    ).updateOne(
     {$set : { ClockInTime: new Date(myDoc.ClockInTime) } } 
    ); 

    if ((++ops % 10000) === 0){ 
     bulk.execute(); 
     bulk = db.ClockTime.initializeUnorderedBulkOp(); 
    } 

    } 
bulk.execute() 
)