MongoCollection.findOneAndUpdate()中的$ inc与$ setOnInsert

时间:2016-11-23 16:27:46

标签: mongodb

我尝试在mongodb中实现for (i = 0; i <= lenstr; i++) { revstr[i] = inputstr[lenstr - i]; } revstr[i] = '\0'; 项目并尝试使用Java API执行以下/ * * /

'server-side counter-versioned'

假设逻辑很简单:如果数据库中没有记录 - 从零开始计数(并使用一个全新的新对象),否则 - 增加计数器。

代码示例失败,并显示: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));

我的假设是在'upsert&#39; mode mongo应该只使用&#34; $ setOnInsert&#34;当没有找到匹配的项目时 - 但它以其他方式工作。

是否可以在 one atomic mongoDB调用中实现此类操作?

PS:MongoDB documentation关于findOneAndUpdate()和upsert()是模糊的 - 至少我不明白为什么这个错误会从他们的描述中产生。

此处也存在类似问题 - findAndModify fails with error: "Cannot update 'field1' and 'field1' at the same time - 已被接受,但同样没有明确的推理。

1 个答案:

答案 0 :(得分:1)

您可以删除$setOnInsert的更新运算符,因为如果文档不存在,它将设置为$inc运算符中指定的值

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

  

如果该字段不存在,$ inc将创建该字段并将该字段设置为指定值。

来自mongo shell的示例:

> 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 }
>