2017-06-17 48 views
0

以下是这种情况:我想用特定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}) 

这看起来太过复杂。我想知道这个解决方案是否有更好的方法?

+0

有办法,但如果你是“真”用'_id'场那么它已经是“独一无二”的,所以一个“upsert”**不会**发生,而您将会收到一个重复的键错误,并且不会有任何改变。其他解决方案基于相同的原理而有所不同,但是'_id'基本上覆盖了它,并且在这种情况下,“upsert”是完全正确的,如前所述。在你的问题中'$ set'或其他更新操作符的缺失确实是比较麻烦的,因为你实际上会在没有它们的情况下“覆盖”其他字段,如“update_time”数据。因此,每秒钟的写入都会尝试在dup键上插入并失败。 –

+0

'$ set'操作员添加 –

+0

我认为更重要**事实**有**不可能重复主键**。由于日期不匹配,不会发生upsert。它的结果将永远是一个重复的关键错误。这是你如何实现你想要的东西的本质。所以如果你在这里讲真相,那么“upsert”已经起作用了。 –

回答

0

您可以先限制搜索,以仅查找具有小于新更新时间的更新的项目。一旦这些选择得到满足,那么你可以像以前一样使用upsert。

db.collection.update(
    { 
    '_id': 'the_specific_id', 
    'update_time': {'$lt': new_date_time} 
    }, 
    { 
    'field_1': 'value_1', 
    'field_2': 'value_2', 
    'update_time': new_date_time 
    }, 
    { 'upsert': true} 
) 
0

您可以使用findOrCreate它用于承诺,但这个包括{upsert:true}声明也可以帮助你在更新,创建机制。

谢谢。

0

正如@Neil伦恩指出,这样做的最简单的方法是:

try: 
    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}) 
except DuplicateKeyError as e: 
    pass