В чем разница между findAndModify и update в MongoDB?

175

Я немного смущен findAndModifyметодом в MongoDB. В чем преимущество этого updateметода? Мне кажется, что сначала он просто возвращает элемент, а затем обновляет его. Но зачем мне сначала возвращать товар? Я прочитал MongoDB: полное руководство, в котором говорится, что оно удобно для манипулирования очередями и выполнения других операций, требующих атомарности в стиле get-and-set. Но я не понял, как это достигается. Может кто-нибудь объяснить это мне?

chaonextdoor
источник

Ответы:

153

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

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

Ася Камская
источник
6
Я все еще немного смущен. Как findAndModifyгарантировать, что никакая другая операция обновления не мешает ему?
chaonextdoor
78
@chaonextdoor findAndModify получает блокировку базы данных при запуске операции, поэтому никакая другая операция не может быть обработана при ее выполнении. Когда он заканчивает операцию, он снимает блокировку.
Лыча
4
На самом деле findAndModify не получает блокировку до тех пор, пока не будет изменена часть запроса. Таким образом, несколько процессов могут иметь возможность обновлять одну и ту же запись.
Марк Унсворт
5
@MarkUnsworth откройте службу поддержки с 10gen - если есть ошибка в блокировке с помощью findAndModify, я могу гарантировать, что инженеры захотят исправить это как можно скорее. Если бы это было так, хотя мы бы увидели, что многие люди сообщают об этом поведении, но findAndModify работает так, как предназначено почти для всех, кто его использует - в случаях, когда казалось, что это не сводится к ошибкам логики или реализации на стороне клиента , но, конечно, в сложных программах всегда может быть ошибка.
Ася Камская
4
@AsyaKamsky Я собирался поспорить с тобой, но потом понял, что ты прав, поэтому теперь я должен извиниться. Сожалею!
Фанки
54

findAndModify возвращает документ, обновление - нет.

Если я правильно понял Дуайта Мерримана (одного из первоначальных авторов mongoDB), я использую update для изменения одного документа, т. Е. («Multi»: false} также является атомарным. В настоящее время это также должно быть быстрее, чем использование эквивалентного обновления с использованием findAndModify.

Янов
источник
31

Из документов MongoDB (выделение добавлено):

  • По умолчанию обе операции изменяют один документ. Однако метод update () с его опцией multi может изменять более одного документа .

  • Если несколько документов соответствуют критериям обновления, для findAndModify () вы можете указать сортировку, чтобы обеспечить некоторую меру контроля над тем, какой документ обновлять. При поведении метода update () по умолчанию вы не можете указать, какой отдельный документ обновлять при совпадении нескольких документов.

  • По умолчанию метод findAndModify () возвращает предварительно измененную версию документа . Чтобы получить обновленный документ, используйте новую опцию. Метод update () возвращает объект WriteResult, который содержит статус операции. Чтобы вернуть обновленный документ, используйте метод find (). Однако другие обновления могли изменить документ между вашим обновлением и поиском документа. Кроме того, если обновление изменило только один документ, но совпало несколько документов, вам потребуется использовать дополнительную логику для идентификации обновленного документа.

  • До MongoDB 3.2 вы не можете указать функцию записи для findAndModify (), чтобы переопределить проблему записи по умолчанию, тогда как вы можете указать функцию записи для метода update () начиная с MongoDB 2.6.

При изменении одного документа оба метода findAndModify () и update () автоматически обновляют документ.

Тамлин
источник
1
Вы всегда можете указать отношение записи к операции обновления. Кроме того, начиная с версии 3.2 (технически 3.1.1), вы также можете указать, что пишите для findAndModify. jira.mongodb.org/browse/SERVER-6558
Ася Камская
Я обнаружил, что в MongDB 3.6, хотя состояния документов findAndModify()по умолчанию изменяют только один документ и update()могут обновлять один или несколько документов, когда я использую arrayFilters, findAndModify()обновляет все совпадения. Может быть, это ошибка?
WesternGun
Нет ошибки - arrayFilters позволяет вам обновлять несколько элементов массива, но они все еще находятся в одном документе.
Ася Камская
10

Одним полезным классом вариантов использования являются счетчики и аналогичные случаи. Например, взгляните на этот код (один из тестов MongoDB): find_and_modify4.js .

Таким образом, findAndModifyвы увеличиваете счетчик и получаете его увеличенное значение за один шаг. Сравните: если вы (A) выполняете эту операцию в два этапа, а кто-то другой (B) выполняет ту же операцию между вашими шагами, то A и B могут получить одно и то же значение последнего счетчика вместо двух разных (только один пример возможных проблем).

Роман Кузьмин
источник
0

Мы использовали findAndModify () для операций Counter (inc или dec) и других случаев мутации отдельных полей. Перенеся наше приложение из Couchbase в MongoDB, я нашел этот API для замены кода, который выполняет GetAndlock (), локального изменения содержимого, замены () для сохранения и получения снова () для получения обновленного документа. С mongoDB я просто использовал этот единственный API, который возвращает обновленный документ.

Манджу Кори
источник