2017-06-17 51 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