2015-07-13 136 views
3

我正在更新一個數據庫,其中有幾百萬個文檔,其中包含少於10個_id衝突。有沒有辦法在Pymongo 3.0中跳過insert_many的現有_id?

我目前使用的PyMongo模塊做使用insert_many通過批量插入:

  1. 查詢數據庫,看是否存在_id
  2. 然後添加文件到一個數組,如果_id不存在
  3. 使用insert_many插入數據庫,每次1000個文檔。

在幾百萬個文檔中只有大約10個衝突,而且我正在查詢每個_id的數據庫。我認爲如果我能削減查詢過程,我可以減少一兩天的整體插入時間。

有沒有類似於upsert的東西,也許只有插入一個文件,如果它不存在?

回答

6

更好的方式來處理這個問題,也有「插入/更新」許多文件以有效的方式是使用Bulk Operations API提交的所有信息在「批」與所有的effecient發送和接收的「奇迴應」確認。

這可以通過兩種方式處理。

首先忽略主鍵或其他指標的任何「重複錯誤」,那麼你可以使用「無序」的形式操作:

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=False) 
for doc in docs: 
    bulk.insert(doc) 

response = bulk.execute() 

的「無序」或false說法存在,使得運營都可以以任何順序執行,並且「完整」批處理將完成,只是在響應中「報告」任何實際錯誤。所以這是一種基本上「忽略」重複和移動的方法。

的另一種方法是大致相同,但使用與$setOnInsert沿着「更新插入」功能性:

bulk = pymongo.bulk.BulkOperationBuilder(collection,ordered=True) 
for doc in docs: 
    bulk.find({ "_id": doc["_id"] }).upsert().updateOne({ 
     "$setOnInsert": doc 
    }) 

response = bulk.execute() 

由此.find()「查詢」部分用於查詢爲一個文件,使用存在的「主鍵「或備選地文檔的」唯一鍵「。如果找不到匹配,則在創建新文檔時會出現「upsert」。由於所有修改內容都在$setOnInsert之內,因此只有在發生「upsert」時纔會修改文檔字段。否則,在文件「匹配」的情況下,對於保存在該操作員下的數據,實際上沒有任何變化。

在這種情況下,「有序」意味着每個語句實際上是以它創建的「相同」順序提交的。此外,任何「錯誤」都會停止更新(在發生錯誤的位置),以便沒有更多的操作會被執行。它是可選的,但可能建議用於正常的「重複」行爲,其中後面的語句「複製」前一個數據。

因此,爲了更有效的寫入,總體思路是使用「Bulk」API並相應地構建您的操作。這裏的選擇實際上取決於來源的「插入順序」是否對您很重要。

當然,"ordered"=False操作適用於insert_many,它實際上在較新的驅動程序版本中使用「批量」操作。但通過使用簡單的API可以「混合」操作的通用界面,您將獲得更大的靈活性。

+0

Gotcha。因此,使用帶有「ordered」= False的insert_many將繼續運行所有插入,而忽略可能彈出的任何錯誤? – SLee

+1

@SLee它應該。有些API已被「修改」,所以結果實際上會引發異常(以前不是這種情況),但「整個」批處理應該執行。另一方面,「upsert」選項不能拋出異常(來自重複鍵),因爲它並不意味着它的任何操作錯誤。正如我所說,*「關鍵在於操作順序是否重要」*。 –

相關問題