Mongodb 如何在mongo中有条件地向上插入文档?
我有一份文件Mongodb 如何在mongo中有条件地向上插入文档?,mongodb,pymongo,Mongodb,Pymongo,我有一份文件 { 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 : 'k
{ 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)
def更新键1(新值、新时间):
record=find_one({key:'key1'})
如果未记录或记录['update_time']<新时间:
更新({key:'key1',value:new_value,update_time:new_time},upsert=True)
显然,这是到数据库的额外往返,但更重要的是,文档没有锁定,并发调用可能会导致数据库中剩余的较低的new_time值。是否有方法仅在条件为真时执行upsert
编辑:只是澄清一下,目的不是为每个键创建多个文档,然后根据查找进行排序。虽然这可以解决我的问题,但这些值会发生很大变化,并会浪费大量空间。似乎是您要寻找的。抱歉,我不熟悉python,因此无法提供代码片段,但命令应该非常简单。您可以执行以下更新:
如果WPCoder对and upsert=True的响应不是您想要的,那么您可能需要$setOnInsert,它尚未实现:。它应该在2.4.0中实现。除了能够以原子方式完成整个任务外,还有两种现有情况需要进行更改,您可以以原子方式处理每种情况:
- 不存在密钥的记录
- 密钥的记录存在,并且其
早于更新时间
新时间
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
)
($setOnInsert
已添加到MongoDB 2.4中)
您可以将这些内容组合在一起以获得所需的内容,例如:
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\u time
字段的记录视为要更新的过期记录,请将{'$lt':new\u time}
更改为{'$not':{'$gte':new\u time}
如果您添加了一个on键
,然后使用update\u time
过滤器和upsert=True
将
您可以捕获错误并检查
code:11000
(唯一约束冲突),以专门处理尝试更新到过去状态的情况。我认为findAndModify无法解决此问题。问题产生于确定是否对记录执行修改。我在文档中看不到这样做的方法。但是如果对象不存在,我想插入它。如果我把它改成upsert,它会添加一个新文档,如果它不是最新的,对吗?是的,如果你的查询是正确的,它应该是这样工作的。确保提供了您的_id列,否则它将创建一个新文档。@WiredPairie执行upsert的原因是您不知道是否存在匹配的文档;你怎么知道它要提供的id?你不需要为\u id
@wiredPairie使用ObjectId
,你的建议有效,但会导致“重复密钥错误收集”。有没有更干净的方法呢?我也有过类似的问题!你能解决这个问题吗?我有完全相似的用例,即使在使用$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)
collection.updateOne({'key': key,
'update_time': {'$lt': new_time}
},
{'$set': {'value': new_value,
'update_time': new_time
}
},
upsert=True
)