Menuntaskan operasi CRUD: memperbarui dokumen dengan updateOne, updateMany, replaceOne, dan findOneAndUpdate, mengenal update operators untuk field dan array, menghapus data, serta pola upsert yang menyatukan insert dan update dalam satu perintah.

Di episode 3 kalian sudah bisa menyimpan dan membaca data. Sekarang tiba waktunya menuntaskan fase CRUD dengan dua operasi terakhir: Update (memperbarui) dan Delete (menghapus). Keduanya terdengar sepele, tapi di dunia nyata justru di sinilah banyak data rusak — update yang salah bisa menghapus field berharga, delete yang salah filter bisa membabat seluruh collection.
Episode 4 akan membangun kepercayaan kalian pada operasi mutasi. Roadmap-nya: pertama kita pelajari empat metode update — updateOne, updateMany, replaceOne, dan findOneAndUpdate; kedua kita bedah update operators untuk field dan array; ketiga kita bahas delete; dan terakhir kita kuasai pola upsert yang cerdas. Mari mulai.
Kedua fungsi ini memperbarui dokumen berdasarkan filter. Perbedaannya hanya pada jumlah dokumen yang diproses: updateOne memperbarui dokumen pertama yang cocok, updateMany memperbarui semua yang cocok. Sintaksnya selalu berbentuk { filter, update }:
db.products.updateOne(
{ name: "Sneaker" },
{ $set: { price: 425000 } }
)
db.products.updateMany(
{ category: "elektronik" },
{ $set: { onSale: true } }
)Perhatikan operator $set — ia menambahkan atau mengubah field tertentu tanpa menyentuh field lain. Ini operator yang paling aman dan paling sering dipakai.
Berbeda dengan $set yang mengubah sebagian field, replaceOne mengganti seluruh dokumen dengan dokumen baru (kecuali _id yang dipertahankan). Ini dipakai saat kalian ingin menulis ulang dokumen sepenuhnya:
db.users.replaceOne(
{ email: "siti@example.com" },
{ name: "Siti Rahmawati", email: "siti@example.com", role: "mentor" }
)Bahaya laten di sini: dokumen lama yang punya field tidak disebutkan di dokumen baru akan hilang. Sebelum memakai replaceOne, pastikan kalian benar-benar ingin menyingkirkan semua field lama.
findOneAndUpdate melakukan update dan langsung mengembalikan dokumen — satu operasi atomik, tanpa perlu query terpisah. Secara default ia mengembalikan dokumen sebelum diubah; gunakan opsi { returnDocument: "after" } untuk mendapatkan versi setelah update:
db.users.findOneAndUpdate(
{ email: "siti@example.com" },
{ $inc: { loginCount: 1 } },
{ returnDocument: "after" }
)Contoh di atas menambah loginCount sebesar 1 dan langsung mengembalikan dokumen hasil update — pola umum untuk counter login atau status proses.
Selain $set, ada operator lain yang melayani pola update berbeda:
| Operator | Fungsi | Contoh |
|---|---|---|
$set | Menambah / mengubah field | { $set: { name: "Baru" } } |
$unset | Menghapus field | { $unset: { fieldSementara: "" } } |
$rename | Mengganti nama field | { $rename: { lama: "baru" } } |
$inc | Menambah / mengurangi angka | { $inc: { stock: -1 } } |
$mul | Mengalikan angka | { $mul: { price: 0.9 } } |
$min / $max | Set jika lebih kecil / besar | { $min: { price: 100 } } |
$currentDate | Set ke waktu sekarang | { $currentDate: { updatedAt: true } } |
db.products.updateOne(
{ name: "Laptop Gaming" },
{
$inc: { stock: -1 },
$mul: { price: 0.95 },
$set: { lastSoldAt: ISODate() },
$currentDate: { updatedAt: true }
}
)Satu panggilan bisa memuat banyak operator sekaligus — semua dieksekusi secara atomik pada dokumen.
Data array adalah kekuatan document database, dan MongoDB punya operator khusus untuk memanipulasinya:
| Operator | Fungsi |
|---|---|
$push | Menambahkan elemen ke akhir array |
$pull | Menghapus elemen yang cocok dengan kondisi |
$addToSet | Menambahkan elemen hanya jika belum ada (menghindari duplikat) |
$pop | Menghapus elemen pertama atau terakhir |
$each | Digabung dengan $push/$addToSet untuk menambah banyak elemen |
$position | Menentukan posisi penyisipan (dengan $push + $each) |
$slice | Membatasi panjang array setelah update |
db.users.updateOne(
{ email: "siti@example.com" },
{
$push: { skills: { $each: ["mongodb", "docker"], $position: 0 } },
$addToSet: { tags: "backend" }
}
)
db.users.updateOne(
{ email: "siti@example.com" },
{ $pull: { skills: "docker" } }
)Contoh pertama menambahkan dua skill sekaligus ke posisi awal array dan menambah tag backend tanpa duplikat. Contoh kedua menarik keluar skill docker. Pola ini sangat berguna untuk daftar, keranjang belanja, atau tags.
Menghapus data di MongoDB semudah memperbaruinya — dan sama berbahayanya:
db.products.deleteOne({ name: "Kaos Polos" })
db.sessions.deleteMany({ expiresAt: { $lt: ISODate() } })deleteOne menghapus dokumen pertama yang cocok, deleteMany menghapus semua yang cocok. Perhatikan contoh kedua: pola pembersihan data kadaluarsa seperti ini sangat umum di dunia nyata.
Seperti findOneAndUpdate, findOneAndDelete menghapus satu dokumen dan langsung mengembalikannya. Berguna saat kalian butuh data yang dihapus untuk diproses lebih lanjut (misal memindahkan ke arsip):
const deleted = db.orders.findOneAndDelete({ _id: ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx") })
deletedDengan ini, kalian bisa mengambil dokumen yang dihapus dan menyimpannya ke collection arsip dalam operasi lanjutan.
Upsert adalah pola cerdas yang menggabungkan insert dan update: jika dokumen yang cocok dengan filter belum ada, MongoDB membuatnya; jika sudah ada, MongoDB memperbaruinya. Aktifkan dengan opsi { upsert: true }:
db.users.updateOne(
{ email: "budi@example.com" },
{ $set: { name: "Budi Santoso", loginCount: 1 } },
{ upsert: true }
)Jalankan perintah yang sama dua kali dan bandingkan hasilnya: pertama kali MongoDB melakukan insert (dengan upsertedId di hasil), kedua kalinya melakukan update. Upsert sangat berguna untuk penghitung kunjungan, sesi user, atau sinkronisasi data dari API eksternal.
Info
Kombinasi upsert dan operator $setOnInsert sangat ampuh. $setOnInsert hanya berlaku saat upsert melakukan insert, bukan update — sempurna untuk field seperti createdAt yang harus diisi hanya sekali. Contoh: db.users.updateOne({ email: "x@example.com" }, { $set: { lastLogin: ISODate() }, $setOnInsert: { createdAt: ISODate() } }, { upsert: true }).
Warning
Sebelum menjalankan deleteMany atau updateMany tanpa filter (atau filter longgar), biasakan menulis db.collection.find({ filter }) dulu untuk melihat berapa banyak dokumen yang akan terpengaruh. Satu filter typo di deleteMany bisa menghapus seluruh collection tanpa bisa di-undo.
Pada episode 4 ini kalian telah menuntaskan operasi CRUD. Untuk Update: updateOne dan updateMany untuk mutasi sebagian, replaceOne untuk penggantian total, serta findOneAndUpdate yang mengembalikan dokumen secara atomik. Untuk Delete: deleteOne, deleteMany, dan findOneAndDelete. Kalian juga menguasai update operators field ($set, $inc, $unset, dan lainnya), operator array ($push, $pull, $addToSet), serta pola upsert yang mengabungkan insert dan update.
Inti yang harus dibawa pulang:
updateOne vs updateMany dibedakan oleh jumlah dokumen yang diproses.$set mengubah field tertentu; replaceOne mengganti seluruh dokumen.findOneAndUpdate dengan returnDocument: "after" mengembalikan versi terbaru.$push, $pull, dan $addToSet menjaga array tetap rapi.upsert: true menciptakan dokumen baru jika filter tidak cocok — waspadai pembuatan tak sengaja.Di episode 5 berikutnya kita memperdalam kemampuan query: Advanced Query Filters & Operators. Kalian akan memakai operator perbandingan $gt, $in, dan $ne, operator logika $and, $or, $nor, operator elemen $exists dan $type, operator array $all, $elemMatch, dan $size, serta belajar sorting, limit, skip, dan pagination. Sampai jumpa di episode 5!