В чем разница между findAndModify и update в MongoDB?
Я немного смущен findAndModify
метод в MongoDB. В чем его преимущество перед update
метод? Мне кажется, что сначала он просто возвращает элемент, а затем обновляет его. Но зачем мне сначала возвращать товар? Я прочитал MongoDB: полное руководство, в котором говорится, что оно удобно для манипулирования очередями и выполнения других операций, требующих атомарности в стиле get-and-set. Но я не понял, как это достигается. Может кто-нибудь объяснить это мне?
6 ответов
Если вы извлекаете элемент, а затем обновляете его, между этими двумя шагами может быть обновление другим потоком. Если вы сначала обновите элемент, а затем получите его, может произойти другое промежуточное обновление, и вы получите другой элемент, отличный от того, что вы обновили.
Выполнение этого "атомарно" означает, что вы гарантированно получите тот же элемент, который обновляете, то есть никакая другая операция не может произойти между ними.
findAndModify
возвращает документ, обновление - нет.
Если я правильно понял Дуайта Мерримана (одного из первоначальных авторов mongoDB), использующего обновление для изменения одного документа, т. Е.("Multi":false} также является атомарным. В настоящее время это также должно быть быстрее, чем выполнение эквивалентного обновления с использованием findAndModify
,
Из документов MongoDB (выделение добавлено):
По умолчанию обе операции изменяют один документ. Однако метод update() с его опцией multi может изменять более одного документа.
Если несколько документов соответствуют критериям обновления, для findAndModify() вы можете указать сортировку, чтобы обеспечить некоторую меру контроля над тем, какой документ обновлять. При поведении метода update() по умолчанию вы не можете указать, какой отдельный документ обновлять при совпадении нескольких документов.
По умолчанию метод findAndModify() возвращает предварительно измененную версию документа. Чтобы получить обновленный документ, используйте новую опцию. Метод update() возвращает объект WriteResult, который содержит состояние операции. Чтобы вернуть обновленный документ, используйте метод find(). Однако другие обновления могли изменить документ между вашим обновлением и поиском документа. Кроме того, если обновление изменило только один документ, но совпало несколько документов, вам потребуется использовать дополнительную логику для идентификации обновленного документа.
Вы не можете указать функцию записи для findAndModify(), чтобы переопределить задачу записи по умолчанию, тогда как, начиная с MongoDB 2.6, вы можете указать функцию записи для метода update().
При изменении одного документа оба метода findAndModify() и update() автоматически обновляют документ.
Одним полезным классом вариантов использования являются счетчики и аналогичные случаи. Например, взгляните на этот код (один из тестов MongoDB): find_and_modify4.js.
Таким образом, с findAndModify
Вы увеличиваете счетчик и получаете его увеличенное значение за один шаг. Сравните: если вы (A) выполняете эту операцию в два этапа, а кто-то другой (B) выполняет ту же операцию между вашими шагами, то A и B могут получить одно и то же значение последнего счетчика вместо двух разных (только один пример возможных проблем).
Это старый, но важный вопрос, и другие ответы привели меня к большему количеству вопросов, пока я не понял: эти два метода очень похожи, и во многих случаях вы можете использовать любой.
- Оба и выполняют атомарные изменения в рамках одного запроса, такие как увеличение счетчика; на самом деле
и параметры во многом идентичны - В обоих случаях атомарное изменение происходит непосредственно в документе, соответствующем запросу, когда сервер находит его, то есть внутренняя блокировка записи в этом документе на долю миллисекунды, которую сервер подтверждает, что запрос действителен, и применяет обновление.
Нет никакой блокировки записи или семафоров на системном уровне, которые может получить пользователь. Полная остановка. MongoDB намеренно не позволяет легко проверить документ, затем изменить его, а затем записать обратно, в то же время каким-то образом не позволяя другим изменить этот документ. (Хотя разработчик может думать, что он этого хочет, это часто является антипаттерном с точки зрения масштабируемости и параллелизма ... в качестве простого примера представьте, что клиент получает блокировку записи, а затем убивается, удерживая ее. Если вам действительно нужна блокировка записи , вы можете внести его в документы и использовать атомарные изменения для его сравнения и настройки, а затем определить свой собственный процесс восстановления для работы с брошенными блокировками и т. д. Но действуйте осторожно, если вы пойдете по этому пути.)
Насколько я могу судить, существуют два основных различия между методами:
- Если вы хотите получить копию документа при обновлении: позволяет только это , возвращая либо оригинал (по умолчанию), либо
запись после обновления, как уже упоминалось; с тобой только получить , а не документ, и, конечно, чтение документа непосредственно до или после не защищает вас от другого процесса, а также изменения записи между вашим чтением и обновлением - Если есть потенциально несколько совпадающих документов: изменяет только один и позволяет настроить
чтобы указать, какой из них следует изменить; может все изменить с помощью хотя по умолчанию используется только один, но не позволяет сказать, какой из них
Таким образом, имеет смысл то, что говорит HungryCoder, что
Мы использовали findAndModify() для операций счетчика (inc или dec), а другие отдельные поля изменяют регистры. Перенося наше приложение с Couchbase на MongoDB, я обнаружил, что этот API заменяет код, который выполняет GetAndlock (), изменяет содержимое локально, replace () для сохранения и снова Get() для получения обновленного документа обратно. В mongoDB я просто использовал этот единственный API, который возвращает обновленный документ.