我有一份文件
{ key : 'key1', value : 'value1', update_time : 100 }
我希望仅在更新(更长)的更新时间内进行更改。我现在正在做的是:
def update_key1(new_value, new_time):
record = find_one( { key : 'key1' } )
if not record or record['update_time'] < new_time:
update( { key : 'key1', value : new_value, update_time : new_time }, upsert=True)
显然这是对数据库的额外往返,但更重要的是,文档没有锁定,并发调用可能会导致数据库中剩余较低的new_time值。是否有办法在条件为真时执行upsert?
编辑:只是为了澄清,目的不是为每个密钥创建多个文档,然后对查找进行排序。虽然这可以解决我的问题,但这些值会发生很大的变化并且会浪费很多空间。
答案 0 :(得分:1)
您可以进行conditional更新:
db.MyObjects.update( { key : "key1", value: { $lt : aValue }},
{ $set : { value : aValue }});
答案 1 :(得分:1)
如果WPCoder使用和upsert = True的响应不是您正在寻找的内容,那么您可能需要$ setOnInsert,但尚未实现:https://jira.mongodb.org/browse/SERVER-340 。它应该实现2.4.0。
答案 2 :(得分:1)
如果不能原子地完成整个事情,那么你想要做出改变的现有条件有两种,你可以原子地处理它们:
update_time
早于new_time
更新密钥的现有记录:
def update_if_stale(key, new_value, new_time):
collection.update({'key': key,
'update_time': {'$lt': new_time}
},
{'$set': {'value': new_value,
'update_time': new_time
}
}
)
如果以前不存在密钥记录,则插入:
def insert_if_missing(key, new_value, new_time):
collection.update({'key': key},
{'$setOnInsert': {'value': new_value,
'update_time': new_time
}
},
upsert=True
)
(MongoDB 2.4中添加了$setOnInsert
)
您可以将这些组合在一起以获得所需内容,例如:
def update_key(key, new_value, new_time):
insert_if_missing(key, new_value, new_time)
update_if_stale(key, new_value, new_time)
但是,根据系统中可能的删除/插入时间标度,您可能需要多次调用(更新/插入/更新)或其他恶作剧。
除此之外:如果您希望记录丢失,update_time
字段将被视为要更新的陈旧记录,请将{'$lt': new_time}}
更改为{'$not': {'$gte': new_time}}
答案 3 :(得分:1)
如果您在key
上添加unique constraint,则updateOne
带有update_time
过滤器和upsert=True
将
collection.updateOne({'key': key,
'update_time': {'$lt': new_time}
},
{'$set': {'value': new_value,
'update_time': new_time
}
},
upsert=True
)
您可以捕获错误并检查code: 11000
(违反唯一约束)以专门处理那些尝试更新为过去状态的情况。
答案 4 :(得分:0)
似乎您正在寻找findAndModify。对不起,我不熟悉python,所以我无法给你一个代码片段,但命令应该非常简单。