2016-11-23 30 views
2

我想實現在MongoDB中一個'server-side counter-versioned'項目,並嘗試使用Java API */

Document dbDoc = dbCollection.findOneAndUpdate(
     new Document("_id", "meta"), 
     new Document("$inc", new Document("version", 1)) 
      .append("$setOnInsert", new Document("version", 0)), 
     new FindOneAndUpdateOptions().upsert(true) 
            .returnDocument(ReturnDocument.AFTER)); 

假定邏輯是做以下/ * 很簡單:如果數據庫中沒有記錄 - 從零開始計數(並且帶有全新的新對象),否則 - 增加計數器。

代碼示例失敗:'Cannot update 'version' and 'version' at the same time'

我的假設是,如果沒有匹配的項目被發現在「更新插入」模式蒙戈應該只用「$ setOnInsert」 - 但它在一些其他的方式工作。

是否可以在實現這樣的操作一個原子 mongoDB調用?


PS:MongoDB documentation關於findOneAndUpdate()和UPSERT()是模糊的 - 至少我可以不知道爲什麼,從他們的描述這個錯誤arizes。

也有類似的問題在這裏 - findAndModify fails with error: "Cannot update 'field1' and 'field1' at the same time - 接受,但再次沒有明確的推理。

+0

我想添加這個例子中,當你有值的嵌套的對象:{_id:1,小時:{0:0,1:0,2:0 }}並且如果文檔不存在或只是想要添加並增加一小時如果有的話,增加一小時。其實這是不可能的,也不違反任何邏輯。 – jtomasrl

回答

1

你可以僅僅刪除的$setOnInsert,因爲這將更新操作將被設置爲在$inc運營商指定的值,如果這個文件不存在

https://docs.mongodb.com/v3.2/reference/operator/update/inc/#behavior

如果該字段不存在, $ inc創建該字段並將該字段設置爲指定的值。從蒙戈外殼

例子:

> db.dropDatabase() 
{ "ok" : 1 } 
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true}) 
{ "_id" : "meta", "version" : 1 } 
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true}) 
{ "_id" : "meta", "version" : 2 } 
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true}) 
{ "_id" : "meta", "version" : 3 } 
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true}) 
{ "_id" : "meta", "version" : 4 } 
> db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {upsert: true, returnNewDocument: true}) 
{ "_id" : "meta", "version" : 5 } 

如果您需要設置一個給定的版本,第一個初始插件,然後MongoDB中不支持任何運營商原子支持這一點,但後續會安全是一個常見的解決方法:

> db.dropDatabase() 
{ "dropped" : "test", "ok" : 1 } 
> function updateMeta(){ 
... function update(){ 
...  return db.test.findOneAndUpdate({_id: "meta"}, { $inc: { version: 1} }, {returnNewDocument: true}); 
... } 
... 
... var result = update(); 
... 
... if(result === null){ 
...  db.test.insert({_id: "meta", version: -10}); 
...  result = update(); 
... } 
... 
... return result; 
... } 
> 
> updateMeta() 
{ "_id" : "meta", "version" : -9 } 
> updateMeta() 
{ "_id" : "meta", "version" : -8 } 
> updateMeta() 
{ "_id" : "meta", "version" : -7 } 
> updateMeta() 
{ "_id" : "meta", "version" : -6 } 
> updateMeta() 
{ "_id" : "meta", "version" : -5 } 
> 
+0

這不完全是我所需要的 - 我想以'0'(零)(或可能是其他數字)作爲初始計數器值開始。 –

+0

@XtraCoder更新了該變體的答案。 –

+0

該變化不是**一個原子mongoDB調用**,這意味着從許多不同的客戶端並行執行相同的功能將導致不可預知的結果。 –