Katalog toko buku tidak pernah berhenti berubah: penerbit merevisi harga, stok berkurang setiap ada pesanan, dan rating pembaca terus bergerak. Setelah insert dan find, kebutuhan berikutnya adalah mengubah data yang sudah tersimpan tanpa harus menghapus lalu memasukkan ulang. Method updateOne(filter, update) menjawab kebutuhan itu: menemukan document yang cocok dengan filter, lalu mengubah isinya lewat update operators.
Peta materi Chapter ini:
- Anatomi
updateOne()dan peran wajib operator$set. - Membaca hasil
matchedCountdanmodifiedCount. - Galat yang muncul bila dokumen update dikirim tanpa operator.
- Pratinjau opsi
upsert.
Mengubah Satu Document dengan $set #
updateOne() menerima dua argument utama: filter untuk menemukan document, dan dokumen update yang menyatakan perubahan. Dokumen update wajib dibungkus update operator — $set adalah yang paling sering dipakai karena mampu mengganti nilai field maupun membuat field baru. Kita mulai dengan menyiapkan data contoh:
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('6ad3882da9fbaec463d48902'),
'1': ObjectId('6ad3882da9fbaec463d48903'),
'2': ObjectId('6ad3882da9fbaec463d48904'),
'3': ObjectId('6ad3882da9fbaec463d48905'),
'4': ObjectId('6ad3882da9fbaec463d48906')
}
}Tiga baris pembuka ini akan menjadi pola tetap sepanjang Section CRUD: use latihan_crud2 berpindah ke database latihan, db.buku.drop() membersihkan collection dari percobaan sebelumnya, dan insertMany() mengisi lima data buku. Sekarang kita turunkan harga Laskar Pelangi menjadi Rp89.000:
db.buku.updateOne({ judul: "Laskar Pelangi" }, { $set: { harga: 89000 } })
db.buku.findOne({ judul: "Laskar Pelangi" })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad3882da9fbaec463d48902'),
judul: 'Laskar Pelangi',
penulis: 'Andrea Hirata',
harga: 89000,
stok: 12,
kategori: 'Fiksi',
tag: [ 'novel', 'bestseller' ],
rating: 4.6
}Mari kita bedah hasilnya:
- Filter
{ judul: "Laskar Pelangi" }mencocokkan tepat satu document — pola filter yang sama persis denganfind(). { $set: { harga: 89000 } }hanya mengganti fieldharga;findOne()membuktikanpenulis,stok,kategori,tag, danratingtetap utuh.- Hasil
matchedCount: 1, modifiedCount: 1melapor: satu document cocok, satu document berubah.
Membaca Hasil matchedCount dan modifiedCount #
Dua angka pada hasil di atas adalah alat diagnosis utama untuk operasi update. matchedCount menghitung document yang cocok dengan filter, sedangkan modifiedCount menghitung yang benar-benar berubah isinya. Tiga skenario yang paling sering muncul:
| Skenario | matchedCount | modifiedCount |
|---|---|---|
| Filter cocok dan nilai baru berbeda | 1 | 1 |
| Filter cocok, tetapi nilai sudah sama | 1 | 0 |
| Filter tidak cocok dengan document mana pun | 0 | 0 |
Skenario kedua sering mengejutkan pemula. Coba jalankan kembali update yang sama persis:
db.buku.updateOne({ judul: "Laskar Pelangi" }, { $set: { harga: 89000 } })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 0,
upsertedCount: 0
}Server menemukan document yang dicari, membandingkan nilai baru dengan nilai lama, lalu memutuskan tidak ada yang perlu ditulis — sehingga modifiedCount tetap 0. Ini bukan galat. Sebaliknya, bila filter tidak menemukan apa pun:
db.buku.updateOne({ judul: "Buku yang Tidak Ada" }, { $set: { harga: 50000 } })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 0
}Kombinasi 0/0 juga bukan galat — perintah sukses dieksekusi, hanya tidak menemukan sasaran. Ketika hasil 0/0 muncul tanpa diduga, periksa kembali filter: kesalahan ketik pada nama field atau nilainya adalah penyebab paling umum.
Dokumen Update Harus Memakai Operator #
Godaan besar bagi pemula adalah menulis dokumen update seperti document biasa pada insertOne() — langsung berisi field dan nilai. MongoDB menolak pendekatan itu:
db.buku.updateOne({ judul: "Laskar Pelangi" }, { harga: 50000 })Output yang Dihasilkan:
Uncaught
MongoInvalidArgumentError: Update document requires atomic operatorsPerhatikan jenisnya: MongoInvalidArgumentError, bukan MongoServerError. Validasi ini terjadi di sisi klien — mongosh memeriksa dokumen update sebelum perintah dikirim ke server, sehingga permintaan yang keliru tidak pernah meninggalkan shell. Pesan Update document requires atomic operators menegaskan aturannya: perubahan harus dinyatakan eksplisit lewat operator seperti $set.
Pratinjau Opsi upsert #
Skenario matchedCount: 0 tadi berakhir tanpa efek — kecuali kita menambahkan opsi { upsert: true }. Dengan opsi itu, MongoDB menyisipkan document baru yang dibentuk dari gabungan field filter dan dokumen update:
db.buku.updateOne(
{ judul: "Rumah Kaca" },
{ $set: { penulis: "Pramoedya Ananta Toer", harga: 98000 } },
{ upsert: true }
)Output yang Dihasilkan:
{
acknowledged: true,
insertedId: ObjectId('6ad3882d9d08d4e3fde1a3ae'),
matchedCount: 0,
modifiedCount: 0,
upsertedCount: 1
}upsertedCount: 1 menandakan satu document baru dibuat, dan _id-nya dilaporkan pada field insertedId. Logika “update bila ada, insert bila tidak” ini penting untuk dibahas tuntas di Chapter Upsert — sekarang kita cukup tahu pintunya ada.
Terakhir, bersihkan database latihan:
db.dropDatabase()Output yang Dihasilkan:
{ ok: 1, dropped: 'latihan_crud2' }Rangkuman #
updateOne(filter, update)mengubah document pertama yang cocok dengan filter; field lain tidak tersentuh.- Dokumen update wajib memakai operator —
$setuntuk mengganti atau membuat field. matchedCountmenghitung yang cocok,modifiedCountyang benar-benar berubah;0/0bukan galat.- Dokumen update polos ditolak
MongoInvalidArgumentErrordi sisi klien sebelum mencapai server. - Opsi
{ upsert: true }mengubah kegagalan cocok menjadi penyisipan document baru.
Satu document sudah terkendali. Chapter berikutnya memperluas kemampuan yang sama ke banyak document sekaligus lewat updateMany().