Подтвердить что ты не робот

Как я могу условно увеличить документ в монго?

У меня есть документ

{ 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)

Очевидно, что это дополнительная обратная связь с db, но что более важно, там нет блокировки документа, а одновременные вызовы могут привести к более низкому значению new_time, оставшемуся в db. Есть ли способ выполнить upsert, только если условие истинно?

РЕДАКТИРОВАТЬ: просто чтобы уточнить, намерение состоит не в том, чтобы создавать несколько документов для каждого ключа, а затем сортировать по поиску. Хотя это решит мою проблему, эти ценности сильно меняются и будут тратить много места.

4b9b3361

Ответ 1

Вы можете сделать условное обновление:

db.MyObjects.update( { key : "key1", value: { $lt : aValue }},
                    { $set : { value : aValue }});

Ответ 2

Если ответ WPCoder с и upsert = True не тот, который вы ищете, вам может понадобиться $setOnInsert, который еще не реализован: https://jira.mongodb.org/browse/SERVER-340. Он должен быть реализован для версии 2.4.0.

Ответ 3

Не имея возможности делать все это атомически, существуют два вида существующих условий, в которых вы хотите внести изменения, и вы можете иметь дело с каждым из них атомарно:

  • нет записи для ключа
  • существует запись для ключа, а ее 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
                      )

($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_time, для обработки обновленной устаревшей записи, измените {'$lt': new_time}} на {'$not': {'$gte': new_time}}

Ответ 4

Кажется, что вы ищете findAndModify. Извините, я не знаком с python, поэтому я не смогу дать вам фрагмент кода, но команда должна быть довольно простой.