upsert, replaceOne и удаление

Три приёма: вставить-если-нет (upsert), заменить документ целиком и удалить ненужное.

upsert — режим обновления, при котором документ создаётся, если ни один не подошёл под фильтр.

upsert: обнови или вставь

Частая задача: «если запись есть — обнови, если нет — создай». Без upsert пришлось бы сначала проверять наличие, потом решать, что делать. Опция { upsert: true } делает это одним запросом:

db.counters.updateOne(
  { _id: "visits" },
  { $inc: { value: 1 } },
  { upsert: true }
)

Если счётчика visits нет — MongoDB создаст документ с этим _id и применит $inc (значение станет 1). Если есть — просто увеличит. В ответе при вставке появится upsertedId:

Результат:

{
  "acknowledged": true,
  "matchedCount": 0,
  "modifiedCount": 0,
  "upsertedId": "visits"
}

Upsert особенно полезен для счётчиков, кешей и синхронизации данных из внешних источников, где нет уверенности, существует ли запись.

replaceOne — полная замена

Иногда нужно именно заменить документ целиком, а не точечно поправить поля. Для этого есть честный replaceOne — он заменяет всё содержимое (кроме _id), но без операторов:

db.products.replaceOne(
  { _id: "SKU-1001" },
  { name: "Кофе молотый", price: 520, inStock: true }
)

Все прежние поля документа исчезнут, останется новый объект. Используйте replaceOne сознательно: когда действительно хотите переписать запись, а не дополнить.

Удаление: deleteOne и deleteMany

deleteOne удаляет первый подходящий документ, deleteMany — все подходящие. Синтаксис фильтра — как в find:

db.users.deleteOne({ name: "Анна" })
db.users.deleteMany({ inStock: false })

Удалить все документы коллекции — пустой фильтр (будьте предельно внимательны, отката нет):

db.logs.deleteMany({})

Если нужно убрать саму коллекцию вместе с индексами — это уже не удаление документов, а drop:

db.logs.drop()

Чем удаление отличается от $unset

Не путайте уровни: deleteOne удаляет документ целиком, а $unset убирает поле внутри документа. Первое — про записи, второе — про их содержимое.

Итог

  • { upsert: true } создаёт документ, если под фильтр ничего не подошло — «обнови или вставь» одним запросом.
  • replaceOne заменяет содержимое документа целиком (кроме _id), без операторов.
  • deleteOne/deleteMany удаляют документы; {} — все; drop() сносит коллекцию.
Проверьте себя
1. Что делает опция upsert: true?
AУдаляет документ, если он найден
BСоздаёт документ, если ни один не подошёл под фильтр, иначе обновляет
CЗаменяет все документы коллекции
DОтключает генерацию _id
2. Чем replaceOne отличается от updateOne с $set?
AreplaceOne меняет одно поле, $set — все
BreplaceOne заменяет документ целиком, а $set правит только указанные поля
CОни идентичны
DreplaceOne работает только с массивами
3. В чём разница между deleteOne и $unset?
AНикакой разницы нет
BdeleteOne удаляет документ целиком, $unset убирает отдельное поле
CdeleteOne удаляет поле, $unset — документ
DОба удаляют коллекцию
Поддержать проект