Обновление: updateOne и updateMany
Как изменить существующие документы и почему почти всегда нужен оператор $set.
updateOne меняет первый подходящий документ, updateMany — все подходящие; оба принимают фильтр и описание изменений.
Структура команды обновления
У методов обновления два аргумента: фильтр (какие документы менять, синтаксис тот же, что в find) и обновление (что именно изменить, с операторами-модификаторами). Поднимем цену одному товару:
db.products.updateOne(
{ name: "Кофе" },
{ $set: { price: 500 } }
)В ответе видно, сколько документов нашлось и сколько реально изменилось:
Результат:
{
"acknowledged": true,
"matchedCount": 1,
"modifiedCount": 1
}$set обязателен: иначе вы перезапишете документ
Это ловушка для новичков. Если передать голый объект без оператора, MongoDB не «дополнит» поля, а заменит документ целиком. Такой вызов сотрёт все остальные поля товара, оставив один price:
// ОПАСНО: это replace, а не update
db.products.updateOne(
{ name: "Кофе" },
{ price: 500 }
)Правильно — заворачивать изменения в $set: он меняет указанные поля, а остальные не трогает. Несуществующее поле $set добавит.
db.products.updateOne(
{ name: "Кофе" },
{ $set: { price: 500, discount: 10 } }
)updateMany — массовое обновление
updateOne остановится на первом совпадении. Чтобы обновить все подходящие документы, нужен updateMany. Пометим все товары из Казани как доступные:
db.products.updateMany(
{ city: "Казань" },
{ $set: { inStock: true } }
)Поднять цену сразу на весь каталог? Фильтр {} совпадает со всеми документами:
db.products.updateMany(
{},
{ $set: { currency: "RUB" } }
)matched и modified — не одно и то же
В ответе два счётчика: matchedCount — сколько документов подошло под фильтр, modifiedCount — сколько реально изменилось. Если новое значение совпадает со старым, документ найден, но не изменён — тогда matched больше modified. Это нормально и помогает понять, что произошло.
Итог
- У обновления два аргумента: фильтр и описание изменений с операторами.
- Без оператора (
$setи др.) документ заменяется целиком — частая и опасная ошибка. updateOneменяет один документ,updateMany— все подходящие; фильтр{}— это «все».