2012-05-20 71 views
18

文件考虑一个简单蒙戈文件结构仅设置值:mongodb的:upserting:如果被插入

{_id,firstTime,lastTime}

客户端需要插入一个文档具有已知ID,或更新现有文档。 'lasttime'应该总是设置为最近的一段时间。对于'firstTime',如果正在插入文档,则应将'firstTime'设置为当前时间。但是,如果文档已经创建,那么'firstTime'保持不变。我想纯粹用upserts来做(避免查找)。

我抓取http://www.mongodb.org/display/DOCS/Updating,但我只是不明白如何完成特定的操作。

我不认为这是不合理的,有$ push和$ addToSet操作可以在数组字段上有效地做到这一点,只是在简单字段上不会这样做。这就像应该有像$ setIf操作。

+0

*如果文档已经创建,该字段应该保持不变*不会调用upsert(如在您的标题中) –

+0

@ om-nom-nom我概述了最简单的情况,我更新了描述,所以有一个总是被更新的字段。 –

+1

看起来像这个功能是针对2.4:https://jira.mongodb.org/browse/SERVER-340 – JohnnyHK

回答

27

我遇到了相同问题,并有用于然而< 2.4 2.4以来的$ setOnInsert运营商没有简单的解决方案让你做到这一点。

db.collection.update(<query>, 
         { $setOnInsert: { "firstTime": <TIMESTAMP> } }, 
         { upsert: true } 
        ) 

查看2.4 release notes of setOnInsert了解更多信息。

1

没有办法只用一个upsert来做到这一点。您必须将其作为2个操作来执行 - 首先尝试插入文档,如果它已经存在,则由于_id索引上重复的键违例,插入将失败。然后,您执行更新操作以将lastTime设置为现在。

+0

恕我直言,这将失败的目的,在做,等待,第一次操作相当于同步查找。我没有看到“尝试失败”并找到并更新的区别...... –

+1

有多个并发作者的查找和更新和更新方法存在争用条件。如果另一个编写者在第一个线程执行读取操作和执行写入操作之间创建/更改文档,则可以结束重写另一个线程执行的写入操作。 – stbrody

+0

这就是为什么我需要它在单个write()操作中,所以要求Mongo以原子方式执行它。 –

1

试图UPSERT基于现有内容文档时,我遇到了一个非常类似的问题 - 也许这个解决方案会为你工作也:

尝试从你的记录删除了_id属性,只有在查询中使用它您更新的部分(你要翻译从pymongo说话......)

myid = doc.get('_id') 
del doc['_id'] 
mycollection.update({'_id':myid}, {'$set':doc}, upsert=True)