Яка різниця між findAndModify та оновленням у MongoDB?


175

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

Відповіді:


153

Якщо ви виберете елемент і потім оновите його, можливо, буде оновлено інший потік між цими двома кроками. Якщо ви оновлюєте елемент спочатку, а потім завантажуєте його, може бути ще одне оновлення між ними, і ви отримаєте інший елемент, ніж те, що ви оновили.

Виконуючи це "атомно", ви гарантуєте, що отримаєте назад той самий елемент, який ви оновлювали - тобто жодна інша операція не може відбутися між ними.


6
Я ще трохи розгублений. Як findAndModifyгарантується відсутність жодної іншої операції оновлення, яка заважає цьому?
chaonextdoor

78
@chaonextdoor findAndModify отримує блокування бази даних під час запуску операції, так що жодна інша операція не може обробляти її під час запуску. Після завершення операції він звільняє замок.
Лича

4
findAndModify насправді не отримує блокування, поки не змінить частину запиту. Таким чином, для декількох процесів можливо оновити одну і ту ж запис.
Марк Unsworth

5
@MarkUnsworth відкрийте справу підтримки з 10gen - якщо є помилка в блокуванні з findAndModify, я можу гарантувати, що інженери захочуть виправити це якнайшвидше. Якби це було так, хоча ми бачимо, що багато людей повідомляють про таку поведінку, але findAndModify працює як розроблений для майже всіх, хто ним користується - випадки, коли, здавалося, це не зводилося до логіки чи помилок реалізації на стороні клієнта , але, звичайно, у складному програмному забезпеченні завжди може бути помилка.
Ася Камський

4
@AsyaKamsky Я думав сперечатися з тобою, але потім зрозумів, що ти маєш рацію, тому зараз я думаю, що мені слід вибачитися. Вибачте!
funkyeah

54

findAndModify повертає документ, оновлення не відбувається.

Якщо я правильно зрозумів Дуайта Меррімана (одного з оригінальних авторів mongoDB), використовуючи оновлення для зміни одного документа, тобто ("multi": false} також є атомним. В даний час це також повинно бути швидше, ніж робити еквівалентне оновлення з використанням findAndModify.


31

З документів MongoDB (наголос додано):

  • За замовчуванням обидві операції змінюють один документ. Однак метод update () з його багатофункціональним варіантом може змінювати більше одного документа .

  • Якщо декілька документів відповідають критеріям оновлення, для findAndModify () ви можете вказати сорт, щоб забезпечити деяку міру контролю над тим, який документ потрібно оновити. При поведінці методу update () за замовчуванням ви не можете вказати, який саме документ потрібно оновити, коли збігається декілька документів.

  • За замовчуванням метод findAndModify () повертає попередньо модифіковану версію документа . Для отримання оновленого документа скористайтеся новою опцією. Метод update () повертає об'єкт WriteResult, який містить статус операції. Щоб повернути оновлений документ, використовуйте метод find (). Однак інші оновлення можуть змінити документ між вашим оновленням та завантаженням документа. Крім того, якщо оновлення змінило лише один документ, але збільшено кілька документів, вам потрібно буде використовувати додаткову логіку для ідентифікації оновленого документа.

  • Перед MongoDB 3.2 ви не можете вказати питання запису для findAndModify (), щоб замінити проблему запису за замовчуванням, тоді як ви можете вказати питання щодо запису до методу update (), починаючи з MongoDB 2.6.

Змінюючи один документ, і метод FindAndModify (), і update () атомним чином оновлюють документ.


1
Ви завжди можете вказати питання щодо запису щодо операції оновлення. Крім того, оскільки в 3.2 (3.1.1 технічно) ви можете вказати питання, що стосуються запису, щоб знайти такожAndModify. 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 (), змінити вміст локально, замінити (), щоб зберегти та Get () знову, щоб отримати оновлений документ назад. З mongoDB я щойно використав цей єдиний API, який повертає оновлений документ.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.