Pada Chapter updateOne() kita sudah melihat galat Update document requires atomic operators: MongoDB menolak dokumen update polos dan menuntut perubahan dinyatakan lewat operator. Operator-operator inilah kosakata kerja seluruh operasi update — $set menulis, $inc menghitung, $push menambah anggota array, dan seterusnya. Chapter ini memetakan semuanya sekaligus menguji yang paling penting di collection buku toko kita.
Operator Field #
Tujuh operator ini bekerja pada field tunggal — membuat, menghapus, atau mengubah nilainya:
| Operator | Tugas | Contoh |
|---|---|---|
$set | Mengisi atau mengganti nilai field | { $set: { harga: 89000 } } |
$unset | Menghapus field dari document | { $unset: { stok: "" } } |
$inc | Menambah (atau mengurangi) nilai numerik | { $inc: { stok: -3 } } |
$mul | Mengalikan nilai numerik | { $mul: { harga: 1.1 } } |
$min | Menulis hanya bila nilai baru lebih kecil | { $min: { harga: 120000 } } |
$max | Menulis hanya bila nilai baru lebih besar | { $max: { rating: 5.0 } } |
$rename | Mengganti nama field | { $rename: { kategori: "genre" } } |
Seperti biasa, kita mulai dari data contoh yang bersih:
use latihan_crud2
db.buku.drop()
db.buku.insertMany([
{ judul: "Laskar Pelangi", penulis: "Andrea Hirata", harga: 95000, stok: 12, kategori: "Fiksi", tag: ["novel", "bestseller"], rating: 4.6 },
{ judul: "Bumi Manusia", penulis: "Pramoedya Ananta Toer", harga: 110000, stok: 8, kategori: "Fiksi", tag: ["novel", "klasik"], rating: 4.8 },
{ judul: "Atomic Habits", penulis: "James Clear", harga: 135000, stok: 20, kategori: "Pengembangan Diri", tag: ["nonfiksi", "bestseller"], rating: 4.7 },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, stok: 0, kategori: "Pengembangan Diri", tag: ["nonfiksi"], rating: 4.5 },
{ judul: "Clean Code", penulis: "Robert C. Martin", harga: 165000, stok: 5, kategori: "Teknologi", tag: ["pemrograman", "bestseller"], rating: 4.4 }
])Output yang Dihasilkan:
switched to db latihan_crud2
true
{
acknowledged: true,
insertedIds: {
'0': ObjectId('6ad3883195780b821157a833'),
'1': ObjectId('6ad3883195780b821157a834'),
'2': ObjectId('6ad3883195780b821157a835'),
'3': ObjectId('6ad3883195780b821157a836'),
'4': ObjectId('6ad3883195780b821157a837')
}
}$set dan $unset adalah pasangan yang paling sering dipakai — satu menulis, satu menghapus. Nilai pada $unset diabaikan; string kosong "" hanyalah konvensi:
db.buku.updateOne({ judul: "Laskar Pelangi" }, { $set: { harga: 89000 }, $unset: { stok: "" } })
db.buku.findOne({ judul: "Laskar Pelangi" })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a833'),
judul: 'Laskar Pelangi',
penulis: 'Andrea Hirata',
harga: 89000,
kategori: 'Fiksi',
tag: [ 'novel', 'bestseller' ],
rating: 4.6
}Hasilnya: harga berubah menjadi 89000 dan field stok tidak lagi ada. $inc bekerja pada nilai numerik — dan bila field belum ada, $inc membuatnya mulai dari nol:
db.buku.updateOne({ judul: "Laskar Pelangi" }, { $inc: { terjual: 10 } })
db.buku.findOne({ judul: "Laskar Pelangi" }, { judul: 1, harga: 1, terjual: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a833'),
judul: 'Laskar Pelangi',
harga: 89000,
terjual: 10
}$mul mengalikan nilai yang ada dengan angka pengali. Cobalah menaikkan harga 10%:
db.buku.updateOne({ judul: "Clean Code" }, { $mul: { harga: 1.1 } })
db.buku.findOne({ judul: "Clean Code" }, { judul: 1, harga: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a837'),
judul: 'Clean Code',
harga: 181500.00000000003
}Dua operator perbandingan melengkapi kelompok ini. $min hanya menulis bila nilai baru lebih kecil dari nilai lama; $max kebalikannya. Pola ini pas untuk menjaga “rekor” — harga promo tidak menimpa harga yang sudah lebih murah:
db.buku.updateOne({ judul: "Atomic Habits" }, { $min: { harga: 120000 }, $max: { rating: 4.9 } })
db.buku.findOne({ judul: "Atomic Habits" }, { judul: 1, harga: 1, rating: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a835'),
judul: 'Atomic Habits',
harga: 120000,
rating: 4.9
}Harga 120000 lebih kecil dari 135000 sehingga ditulis; rating 4.9 lebih besar dari 4.7 sehingga ikut naik. Terakhir, $rename memindahkan nilai ke nama field baru — field _id dan array yang dijadikan sumber index tidak boleh di-rename:
db.buku.updateOne({ judul: "Filosofi Teras" }, { $rename: { kategori: "genre" } })
db.buku.findOne({ judul: "Filosofi Teras" }, { judul: 1, genre: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a836'),
judul: 'Filosofi Teras',
genre: 'Pengembangan Diri'
}Operator Array #
Lima operator ini mengelola isi array — pada data kita, array tag:
| Operator | Tugas |
|---|---|
$push | Menambah elemen ke akhir array — duplikat diperbolehkan |
$addToSet | Menambah elemen hanya bila belum ada di array |
$pop | Membuang elemen pertama (-1) atau terakhir (1) |
$pull | Membuang semua elemen yang cocok dengan nilai atau kondisi |
$pullAll | Membuang semua elemen yang tercantum pada daftar |
$push menempel satu nilai ke akhir array; dengan modifier $each, ia menempel banyak nilai sekaligus:
db.buku.updateOne({ judul: "Bumi Manusia" }, { $push: { tag: "sastra" } })
db.buku.updateOne({ judul: "Bumi Manusia" }, { $push: { tag: { $each: ["kampus", "buku-wajib"] } } })
db.buku.findOne({ judul: "Bumi Manusia" }, { judul: 1, tag: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a834'),
judul: 'Bumi Manusia',
tag: [ 'novel', 'klasik', 'sastra', 'kampus', 'buku-wajib' ]
}$push juga menerima $sort dan $slice sebagai modifier — kombinasi yang umum untuk menjaga “N nilai teratas”. Di bawah ini seluruh isi tag diurutkan alfabetis lalu dipangkas menjadi tiga:
db.buku.updateOne({ judul: "Bumi Manusia" }, { $push: { tag: { $each: ["sekolah", "budaya"], $sort: 1, $slice: 3 } } })
db.buku.findOne({ judul: "Bumi Manusia" }, { judul: 1, tag: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a834'),
judul: 'Bumi Manusia',
tag: [ 'budaya', 'buku-wajib', 'kampus' ]
}Sekarang perbedaan yang paling sering menjebak: $push tidak memeriksa duplikat, sedangkan $addToSet memeriksa:
db.buku.updateOne({ judul: "Atomic Habits" }, { $push: { tag: "bestseller" } })
db.buku.updateOne({ judul: "Atomic Habits" }, { $addToSet: { tag: "bestseller" } })
db.buku.updateOne({ judul: "Atomic Habits" }, { $addToSet: { tag: { $each: ["bestseller", "manajemen-diri"] } } })
db.buku.findOne({ judul: "Atomic Habits" }, { judul: 1, tag: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 0,
upsertedCount: 0
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a835'),
judul: 'Atomic Habits',
tag: [ 'nonfiksi', 'bestseller', 'bestseller', 'manajemen-diri' ]
}Bacalah tiga hasil di atas secara berurutan: $push menambah bestseller kedua tanpa protes (modifiedCount: 1), $addToSet dengan nilai yang sudah ada tidak mengubah apa pun (modifiedCount: 0), dan $addToSet dengan $each hanya memasukkan manajemen-diri yang memang baru.
Untuk membuang elemen, $pop memilih berdasarkan posisi — -1 untuk pertama, 1 untuk terakhir:
db.buku.updateOne({ judul: "Bumi Manusia" }, { $pop: { tag: 1 } })
db.buku.updateOne({ judul: "Bumi Manusia" }, { $pop: { tag: -1 } })
db.buku.findOne({ judul: "Bumi Manusia" }, { judul: 1, tag: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a834'),
judul: 'Bumi Manusia',
tag: [ 'buku-wajib' ]
}$pop: 1 membuang kampus (posisi terakhir), lalu $pop: -1 membuang budaya (posisi pertama). Sementara itu, $pull dan $pullAll membuang berdasarkan isi: $pull menerima nilai eksak maupun kondisi query, dan menghapus semua kemunculannya; $pullAll hanya menerima daftar nilai eksak:
db.buku.updateOne({ judul: "Atomic Habits" }, { $pull: { tag: "bestseller" } })
db.buku.updateOne({ judul: "Atomic Habits" }, { $pullAll: { tag: ["nonfiksi", "manajemen-diri"] } })
db.buku.findOne({ judul: "Atomic Habits" }, { judul: 1, tag: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883195780b821157a835'),
judul: 'Atomic Habits',
tag: []
}Satu $pull menghapus kedua salinan bestseller sekaligus — perilaku “semua yang cocok” ini sejajar dengan semangat updateMany().
Operator Khusus: $setOnInsert, $, dan $[] #
Tiga operator penutup mengisi ceruk tertentu. $setOnInsert hanya bekerja ketika opsi upsert: true benar-benar menyisipkan document baru — sempurna untuk field yang cukup diisi sekali seumur hidup data:
db.buku.updateOne(
{ judul: "Buku Hitung Stok" },
{ $set: { kategori: "Referensi" }, $setOnInsert: { dibuatPada: "2026-10-17" } },
{ upsert: true }
)
db.buku.updateOne(
{ judul: "Buku Hitung Stok" },
{ $set: { kategori: "Referensi" }, $setOnInsert: { dibuatPada: "TIDAK BERLAKU" } },
{ upsert: true }
)
db.buku.findOne({ judul: "Buku Hitung Stok" })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: ObjectId('6ad388329d08d4e3fde1a3af'),
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 1
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 0,
upsertedCount: 0
}
{
_id: ObjectId('6ad388329d08d4e3fde1a3af'),
judul: 'Buku Hitung Stok',
dibuatPada: '2026-10-17',
kategori: 'Referensi'
}Panggilan kedua menemukan document yang sudah ada, sehingga $setOnInsert: { dibuatPada: "TIDAK BERLAKU" } diabaikan sama sekali — nilai 2026-10-17 dari penyisipan pertama tetap bertahan.
Dua operator terakhir menunjuk posisi elemen array. Operator positional $ merujuk elemen pertama yang cocok dengan filter — pada contoh berikut, ulasan milik Siti:
db.buku.insertOne({ judul: "Rumah Kaca", penulis: "Pramoedya Ananta Toer", harga: 98000, stok: 4, ulasan: [ { pengguna: "Budi", bintang: 5 }, { pengguna: "Siti", bintang: 4 } ] })
db.buku.updateOne({ judul: "Rumah Kaca", "ulasan.pengguna": "Siti" }, { $set: { "ulasan.$.teks": "Petualangan yang memikat" } })
db.buku.findOne({ judul: "Rumah Kaca" }, { judul: 1, ulasan: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: ObjectId('6ad3883295780b821157a838')
}
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883295780b821157a838'),
judul: 'Rumah Kaca',
ulasan: [
{ pengguna: 'Budi', bintang: 5 },
{ pengguna: 'Siti', bintang: 4, teks: 'Petualangan yang memikat' }
]
}Filter "ulasan.pengguna": "Siti" menandai elemen kedua; ulasan.$ lalu merujuk tepat ke elemen itu. Adapun $[] menunjuk semua elemen array sekaligus:
db.buku.updateOne({ judul: "Rumah Kaca" }, { $set: { "ulasan.$[].diverifikasi": true } })
db.buku.findOne({ judul: "Rumah Kaca" }, { judul: 1, ulasan: 1 })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3883295780b821157a838'),
judul: 'Rumah Kaca',
ulasan: [
{ pengguna: 'Budi', bintang: 5, diverifikasi: true },
{
pengguna: 'Siti',
bintang: 4,
teks: 'Petualangan yang memikat',
diverifikasi: true
}
]
}Untuk seleksi elemen yang lebih bebas, MongoDB menyediakan arrayFilters sebagai opsi tambahan — di luar cakupan Section ini, tetapi pola $ dan $[] di atas sudah menutup kebutuhan paling umum. Terakhir, bersihkan database latihan:
db.dropDatabase()Output yang Dihasilkan:
{ ok: 1, dropped: 'latihan_crud2' }Rangkuman #
- Operator field:
$setmenulis,$unsetmenghapus,$incmenambah (mulai dari 0 bila field baru),$mulmengalikan,$min/$maxmenjaga batas,$renamememindahkan nama. $muldengan pecahan menghasilkan double — waspadai untuk nilai uang.$pushmembiarkan duplikat;$addToSetmenolak nilai yang sudah ada — pilih sesuai makna array.$popmembuang berdasarkan posisi;$pull(nilai/kondisi, semua kemunculan) dan$pullAll(daftar nilai) membuang berdasarkan isi.$setOnInserthanya berlaku saat upsert menyisipkan;$menunjuk elemen yang cocok filter,$[]menunjuk semua elemen.
Kosakata update lengkap. Chapter berikutnya menempuh jalur berbeda untuk kasus “ganti total”: replaceOne().