2015-10-14 152 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