2015-10-14 194 views
2

我必須說我不是一個真正的mongoDB專家,但這正是我想要做的。MongoDB:插入唯一索引

我有一個應用程序可以在每次打開應用程序時獲得「食物」對象的源,該源自外部Web API服務接收。由於與外部API服務的ToS協議,我只能爲每個這些對象保存獨特的「food」ID。

現在,每次打開應用程序時,我都會得到食物對象的飼料,我只想將食物對象ID(「foodId」)保存在我的mongoDB中。因此,每次打開應用程序時,我都決定做一個補充。我不知道這是否是寫UPSERT方法,你可以看到的查詢參數和更新PARAMS是相同的最佳途徑,都涉及到「foodId」:

    Query query = new Query(); 
        query.addCriteria(Criteria.where("foodId").in(foodIdfromApi)); 
        Update update = new Update(); 
        update.set("foodId", foodIdfromApi); 
        mongoTemplate.upsert(query, update, Food.class); 

由於「foodId」是獨一無二的,我已經創建的「foodId」

這是MongoDB的唯一索引: http://docs.mongodb.org/manual/reference/method/db.collection.update/#upsert-option

要防止的MongoDB從插入相同的文檔超過一次, 創建名稱的唯一索引領域。使用唯一索引,如果 多個應用程序使用upsert:true發佈相同的更新,則一個update()將成功插入一個新文檔。

其餘的操作要麼:當他們試圖 插入重複

更新新插入的文件,或者失敗。如果操作由於重複的 索引鍵錯誤而失敗,則應用程序可能會重試將作爲更新操作成功執行的操作。

我的應用程序在第一次運行時成功下載了Feed。但隨後,每次我想要做一個upsert(每次打開我的應用程序時)它都會給我重複的索引鍵錯誤。

寫,錯誤代碼11000和錯誤消息失敗「E11000複製 關鍵錯誤索引

我不想刪除唯一索引再有就是複製可能存在食物對象的可能性。我如何解決這個問題?

+0

Mongotemplate是java驅動程序的mongo模板。 – Simon

回答

1

你沒有刪除唯一的索引是正確的。這在mongo中是必要的,正如你在文檔中指出的那樣。

要解決他們的選擇,如果在嘗試upsert時出現問題時拋出錯誤,則應該捕獲錯誤並重試。

我沒有使用mongo模板,但這裏有一個使用Java驅動程序的例子。你可以嘗試類似的東西:

MongoCollection<Document> collection = mongo.getCollection("Revenue"); 
    UpdateResult result; 
    try { 
     result = collection.replaceOne(searchDoc, repsertDoc, new UpdateOptions().upsert(true)); 
    } catch (MongoException e) { 
     // Retry once on error, can sleep here too if you'd like 
     result = collection.replaceOne(searchDoc, repsertDoc, new UpdateOptions().upsert(true)); 
     // If this attempt fails, can always re-try again or fail 
    } 
+1

如果爭用中有兩個以上的作者,此實現將失敗。一個完整的實現將使用遞歸函數,在每次遞歸之前呈指數遞增的延遲。一般來說,由於像這樣的邊緣案例,爲樂觀系統編程客戶端可能非常棘手。 – Eric

+1

我已經提到 - 如果在嘗試upsert時出現問題,您應該捕獲錯誤並重試。 '也在代碼中的註釋'如果這個嘗試失敗了,總是可以重新嘗試或失敗'。有些情況下,即使延遲時間增加,也不需要自動重試,這取決於實際情況中的每個用例。 – Cuga