以下是这种情况:我想用特定ID更新文档,并且其update_time比较新的文档更旧,如果找不到这样的文档,请使用较新的文档创建一个文档一。使用特定查询更新的更好方法
第一个解决方案给我的是:
db.collection.update(
{
'_id': 'the_specific_id',
'update_time': {'$lt': new_date_time}
},
{
'$set' :{
'field_1': 'value_1',
'field_2': 'value_2',
'update_time': new_data_time
}
},
{ 'upsert': true}
)
在这个解决方案中,如果文档被发现,然后更新是好的。如果由于找不到'_id'而找不到doc,upsert很好。但是,如果找不到doc,因为db中的doc具有较新的'update_time',则后续upsert不正确(因为主键重复)。
所以我有这个(psudo代码)结束:
try:
db.collection.insert({
'_id': 'the_specific_id',
'field1': 'value1',
'field2': 'value2',
'update_time': new_date_time
})
except Exception as e:
if e.message.find('duplication'):
db.collection.update(
{
'_id': 'the_specific_id',
'update_time': {'$lt': new_date_time}
},
{
'$set' : {
'field_1': 'value_1',
'field_2': 'value_2',
'update_time': new_data_time
}
},
{ 'upsert': false})
这看起来太过复杂。我想知道这个解决方案是否有更好的方法?
有办法,但如果你是“真”用'_id'场那么它已经是“独一无二”的,所以一个“upsert”**不会**发生,而您将会收到一个重复的键错误,并且不会有任何改变。其他解决方案基于相同的原理而有所不同,但是'_id'基本上覆盖了它,并且在这种情况下,“upsert”是完全正确的,如前所述。在你的问题中'$ set'或其他更新操作符的缺失确实是比较麻烦的,因为你实际上会在没有它们的情况下“覆盖”其他字段,如“update_time”数据。因此,每秒钟的写入都会尝试在dup键上插入并失败。 –
'$ set'操作员添加 –
我认为更重要**事实**有**不可能重复主键**。由于日期不匹配,不会发生upsert。它的结果将永远是一个重复的关键错误。这是你如何实现你想要的东西的本质。所以如果你在这里讲真相,那么“upsert”已经起作用了。 –