Проблемы атомарности MongoDB - изменение документа в памяти - PullRequest
5 голосов
/ 06 марта 2012

Я работаю с MongoDB над моим текущим проектом и немного смущен правильным подходом к созданию поддержки одновременных модификаций.

У меня есть массив объектов. Когда приходит запрос, я хочу проверить последний элемент в этом массиве и принять условное решение о том, как ответить. Мой код выглядит примерно так:

# Find the last object ID in the array.
last_element_id = str(document['objects'][-1])
if last_element_id != the_element_id_the_request_is_responding_to:
    db.documents.insert({
        ...
    })
else:
    # Append the response to the end of the array.
    document['objects'].append(new_element_id)
    db.documents.save(document)

Меня беспокоит ситуация, в которой:

  1. При обработке запроса A я считаю, что last_element_id действителен, и ответ должен быть добавлен в конец списка.
  2. Перед тем завершены операции append () и save (), другой запрос, B, обрабатываются.
  3. B также видит, что last_element_id действителен, append () ответ и сохраняет ().
  4. Теперь ответ А поставлен в очередь в конец массива, но ответ больше не следует предполагаемому 'last_element_id' с тех пор, как ответ B проскользнул заранее.

Как правильно обращаться с такой логикой в ​​модели атомарности Монго? Я не хочу использовать блокировки, если смогу их избежать, поскольку приложение WSGI может одновременно выполняться в нескольких процессах.

Спасибо!

Ответы [ 2 ]

1 голос
/ 07 марта 2012

Вы можете использовать findAndModify для атомарной обработки транзакции (по крайней мере, в этом случае).

Эта команда принимает флаг upsert, который можно использовать для обновления или вставки документа на основеего existence.Проверьте приведенный ниже пример

> db.upsertTest.find()
{ "_id" : 1, "arr" : [ 1 ] }

, и при вводе этой команды с запросом _id:1 новый элемент будет добавлен (добавлен) в arr

> db.upsertTest.findAndModify({query: {_id:1},update:{$push:{arr:2}},upsert:true,"new":true})
{ "_id" : 1, "arr" : [ 1, 2 ] }

, и это создаст новый элемент, поскольку_id:2 уже не существует

> db.upsertTest.findAndModify({query: {_id:2},update:{$push:{arr:2}},upsert:true,"new":true})
{ "_id" : 2, "arr" : [ 2 ] }

> db.upsertTest.find()
{ "_id" : 1, "arr" : [ 1, 2 ] }
{ "_id" : 2, "arr" : [ 2 ] }

Надеюсь, это поможет.

1 голос
/ 06 марта 2012

Вы можете использовать оптимистическую блокировку .., один из способов - добавить поле с именем version в документ, а затем увеличивать его при каждом обновлении, а при обновлении убедиться, что версия в документе совпадает с версией документа.Вы читаете в.

Я мог бы дать более подробную информацию, но это довольно хорошо задокументировано в http://www.mongodb.org/display/DOCS/Atomic+Operations#AtomicOperations-%22UpdateifCurrent%22

Дайте мне знать, если это работает для вас,

...