Ada kalanya perbaikan sebagian field tidak lagi masuk akal: data buku hasil impor salah total, atau struktur document lama mau dibetulkan sekaligus. Untuk kasus “ganti seluruh isi” ini MongoDB menyediakan replaceOne(filter, replacement) — menemukan document yang cocok filter, lalu mengganti isinya dengan document baru yang kita sediakan. Perilakinya berbeda fundamental dari updateOne() + $set, dan perbedaan itu penting dipahami sebelum dipakai.
Mengganti Seluruh Isi Document #
replaceOne() menerima filter dan dokumen pengganti — bukan dokumen update. Seluruh isi document lama dibuang dan diganti dokumen pengganti tersebut; satu-satunya bagian yang bertahan adalah _id. Kita buktikan dengan 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('6ad38834b83baea6cd64d4ee'),
'1': ObjectId('6ad38834b83baea6cd64d4ef'),
'2': ObjectId('6ad38834b83baea6cd64d4f0'),
'3': ObjectId('6ad38834b83baea6cd64d4f1'),
'4': ObjectId('6ad38834b83baea6cd64d4f2')
}
}Simpan dulu potongan Filosofi Teras sebelum penggantian — tag dan rating-nya akan sengaja kita tinggalkan:
db.buku.findOne({ judul: "Filosofi Teras" })Output yang Dihasilkan:
{
_id: ObjectId('6ad38834b83baea6cd64d4f1'),
judul: 'Filosofi Teras',
penulis: 'Henry Manampiring',
harga: 89000,
stok: 0,
kategori: 'Pengembangan Diri',
tag: [ 'nonfiksi' ],
rating: 4.5
}Sekarang ganti document tersebut dengan versi yang lebih ringkas — stok sudah terisi ulang, sementara tag dan rating sengaja tidak kita bawa:
db.buku.replaceOne(
{ judul: "Filosofi Teras" },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, stok: 15, kategori: "Pengembangan Diri" }
)
db.buku.findOne({ judul: "Filosofi Teras" })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad38834b83baea6cd64d4f1'),
judul: 'Filosofi Teras',
penulis: 'Henry Manampiring',
harga: 89000,
stok: 15,
kategori: 'Pengembangan Diri'
}Bandingkan kedua potongan di atas: nilai _id persis sama, stok naik dari 0 ke 15, dan field tag serta rating hilang — dokumen pengganti memang tidak memuatnya. Inilah makna “ganti total”: apa pun yang tidak ditulis ulang, dibuang.
Kapan pola ini alami? Ketika sumber data memang mengirim record utuh: hasil impor dari sistem pemasok, data hasil migrasi dari database lama, atau perbaikan menyeluruh setelah struktur document berubah. Bila yang berubah hanya satu-dua field, updateOne() + $set tetap lebih aman — field yang terlupa ditulis ulang tidak akan ikut terbuang.
_id Tetap dan Tidak Bisa Diganti #
_id bersifat immutable, dan replaceOne() mempertahankannya secara otomatis. Namun bila dokumen pengganti mencantumkan _id yang berbeda dengan document lama, server menolak:
db.buku.replaceOne({ judul: "Clean Code" }, { _id: 1, judul: "Clean Code Edisi 2" })Output yang Dihasilkan:
Uncaught
MongoServerError: Plan executor error during update :: caused by :: After applying the update, the (immutable) field '_id' was found to have been altered to _id: 1Mencantumkan _id yang sama dengan document lama justru sah. Pola ini berguna saat dokumen pengganti dibangun dari document lama — misalnya hasil edit form aplikasi yang mengirim kembali seluruh isi record beserta _id-nya:
const lama = db.buku.findOne({ judul: "Clean Code" })
db.buku.replaceOne({ judul: "Clean Code" }, { _id: lama._id, judul: "Clean Code Edisi 2", harga: 175000 })
db.buku.findOne({ judul: "Clean Code Edisi 2" })Output yang Dihasilkan:
{
acknowledged: true,
insertedId: null,
matchedCount: 1,
modifiedCount: 1,
upsertedCount: 0
}
{
_id: ObjectId('6ad38834b83baea6cd64d4f2'),
judul: 'Clean Code Edisi 2',
harga: 175000
}Perhatikan dua hal pada hasilnya: _id document tidak berubah (persis seperti document Clean Code lama), dan isinya kini hanya judul serta harga — field penulis ikut terbuang karena dokumen pengganti tidak memuatnya, konsisten dengan aturan “ganti total” di bagian pertama.
replaceOne atau updateOne dengan $set #
Dua method ini hampir tertukar dari nama, tetapi aturan isinya berlawanan. updateOne() menuntut update operator dan mempertahankan field lain; replaceOne() menerima document biasa dan membuang field lain. Dokumen pengganti yang mencoba memakai operator pun ditolak:
db.buku.replaceOne({ judul: "Bumi Manusia" }, { $set: { harga: 105000 } })Output yang Dihasilkan:
Uncaught
MongoInvalidArgumentError: Replacement document must not contain atomic operatorsPeta keputusannya:
| Aspek | replaceOne() | updateOne() + $set |
|---|---|---|
| Field yang tidak disebut | Hilang, diganti total | Tetap ada |
_id | Dipertahankan dari document lama | Tidak tersentuh |
| Isi argument kedua | Document biasa — operator dilarang | Wajib update operator |
| Cocok untuk | Impor ulang, perombakan struktur | Perubahan sebagian field |
Satu kemiripan penting: replaceOne() juga menerima opsi { upsert: true } — bila filter tidak menemukan document, dokumen pengganti disisipkan sebagai document baru. Kita lihat perilakunya tuntas di Chapter Upsert.
Sebagai penutup, bersihkan database latihan:
db.dropDatabase()Output yang Dihasilkan:
{ ok: 1, dropped: 'latihan_crud2' }Rangkuman #
replaceOne(filter, replacement)mengganti seluruh isi document; hanya_idyang bertahan.- Field yang tidak ada di dokumen pengganti akan hilang — pastikan memang itulah niatnya.
_idimmutable: mencantumkan_idbeda ditolak server, mencantumkan_idsama diperbolehkan.- Dokumen pengganti tidak boleh memakai update operator — cermin kebalikan dari aturan
updateOne(). - Untuk perubahan sebagian field,
updateOne()+$settetap pilihan yang tepat.
Sisi penulisan data tinggal satu tema terakhir: penghapusan, dimulai dari deleteOne() di Chapter berikutnya.