Ce face upsert: true și $setOnInsert
Opțiunea upsert: true (update + insert) se poate da la updateOne, updateMany, replaceOne și findOneAndUpdate. Dacă filtrul găsește un document, acesta este actualizat normal. Dacă nu, MongoDB creează unul nou din câmpurile de egalitate ale filtrului plus modificările din update.
$setOnInsert (MongoDB 2.4+) setează câmpuri doar atunci când documentul este creat, de exemplu data creării sau un status inițial. La actualizările ulterioare, aceste câmpuri nu sunt atinse. În rezultat, upsertedCount: 1 și insertedId arată că s-a creat un document.
Parametri
| Parametru | Descriere |
|---|---|
upsert: true |
Creează documentul dacă filtrul nu găsește nimic. |
$setOnInsert |
Câmpuri scrise doar la creare. |
Ce returnează
Un rezultat cu matchedCount, modifiedCount, upsertedCount și insertedId (ID-ul documentului creat sau null).
Exemple
Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.
use magazin
db.comenzi.insertMany([
{ _id: 1, client: 'Ana', oras: 'Iași', total: 120, status: 'livrata', produse: ['caiet', 'pix'] },
{ _id: 2, client: 'Dan', oras: 'Cluj', total: 85, status: 'noua', produse: ['carte'] },
{ _id: 3, client: 'Ioana', oras: 'Iași', total: 240, status: 'livrata', produse: ['rucsac', 'caiet', 'pix'] },
{ _id: 4, client: 'Mihai', oras: 'Brașov', total: 60, status: 'anulata', produse: [] }
])
Exemplul 1: Comanda 5 nu există: este creată
Documentul nou primește _id: 5 din filtru, câmpurile din $set și statusul din $setOnInsert.
db.comenzi.updateOne(
{ _id: 5 },
{ $set: { client: 'Elena', total: 99 }, $setOnInsert: { status: 'noua' } },
{ upsert: true }
)
Ieșire în mongosh
{
acknowledged: true,
insertedId: 5,
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 1
}
Exemplul 2: Aceeași comandă rulată din nou: actualizare
Acum documentul există (după exemplul 1), deci $setOnInsert este ignorat; valorile din $set sunt deja aceleași, așa că modifiedCount este 0.
db.comenzi.updateOne(
{ _id: 5 },
{ $set: { client: 'Elena', total: 99 }, $setOnInsert: { status: 'noua' } },
{ upsert: true }
)
Ieșire în mongosh
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 0,
upsertedCount: 0
}
Exemplul 3: Contor de vizite pe client
Filtrul nu găsește documentul, așa că se creează unul cu client și oras din filtru și vizite: 1.
db.vizite.updateOne({ client: 'Radu', oras: 'Cluj' }, { $inc: { vizite: 1 } }, { upsert: true })
Ieșire în mongosh
{
acknowledged: true,
insertedId: ObjectId('6addcc18f1a2b3c4d5e6f703'),
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 1
}
Greșeli frecvente
- Fără un index unic pe câmpurile din filtru, două upsert-uri simultane pot crea două documente identice. Pune un index unic pe cheia folosită (
client,email). - Câmpurile din filtru care nu sunt egalități simple (de exemplu
{ total: { $gt: 100 } }) nu sunt copiate în documentul nou. - Nu pune același câmp și în
$set, și în$setOnInsert: primești o eroare de conflict.
Comenzi înrudite
replaceOne(): Înlocuiește complet primul document găsit cu un document nou; câmpurile care nu apar în documentul nou dispar.findOneAndUpdate(): Actualizează un document și îl întoarce, atomic, într-un singur pas; există și findOneAndDelete și findOneAndReplace.createIndex() cu unique: true: Un index unic garantează că două documente nu pot avea aceeași valoare într-un câmp, de exemplu același email.bulkWrite(): Trimite mai multe operații de scriere (inserări, actualizări, ștergeri) către o colecție într-o singură cerere.