deleteOne dan deleteMany

Menghapus dokumen secara terkendali dengan deleteOne dan deleteMany beserta disiplin penghapusannya.

Daftar isi

Topik ini membahas penghapusan dokumen dengan metode deleteOne dan deleteMany beserta hasil kembalian deletedCount. Pembahasan mencakup perilaku deleteOne ketika filternya cocok dengan lebih dari satu dokumen, penghapusan massal dengan filter, serta disiplin pemfilteran yang menjaga penghapusan tetap terkendali. Seluruh contoh dijalankan pada koleksi buku di basis data perpustakaan dengan data contoh yang diisi di awal, sehingga jumlah dokumen yang tersisa pada setiap langkah dapat diverifikasi.

Menghapus satu dokumen dengan deleteOne#

Metode deleteOne menghapus satu dokumen yang cocok dengan filter yang diberikan. Hasil kembaliannya memuat acknowledged beserta deletedCount, yaitu jumlah dokumen yang benar-benar terhapus. Metode ini tidak mengembalikan isi dokumen yang terhapus. Apabila isi dokumen masih dibutuhkan sekali sebelum penghapusan, baca dokumen tersebut terlebih dahulu.

Siapkan data contoh berupa enam buku, tiga di antaranya bermasalah karena stoknya nol dan kondisinya rusak atau hilang.

mongosh
use perpustakaan
text Keluaran
switched to db perpustakaan
mongosh
db.buku.insertMany([
  { judul: "Dasar Pemrograman", pengarang: "Budi Santoso", tahun: 2019, stok: 3, kondisi: "baik" },
  { judul: "Jaringan Komputer", pengarang: "Ali Rahman", tahun: 2018, stok: 0, kondisi: "rusak" },
  { judul: "Basis Data Modern", pengarang: "Citra Melati", tahun: 2022, stok: 5, kondisi: "baik" },
  { judul: "Statistika Dasar", pengarang: "Rina Wulandari", tahun: 2020, stok: 0, kondisi: "rusak" },
  { judul: "Algoritma Lanjutan", pengarang: "Budi Santoso", tahun: 2021, stok: 2, kondisi: "baik" },
  { judul: "Sistem Operasi", pengarang: "Dewi Kartika", tahun: 2017, stok: 0, kondisi: "hilang" }
])
text Keluaran
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('6ae8937bf2d38457a28de666'),
    '1': ObjectId('6ae8937bf2d38457a28de667'),
    '2': ObjectId('6ae8937bf2d38457a28de668'),
    '3': ObjectId('6ae8937bf2d38457a28de669'),
    '4': ObjectId('6ae8937bf2d38457a28de66a'),
    '5': ObjectId('6ae8937bf2d38457a28de66b')
  }
}
mongosh
db.buku.countDocuments()
text Keluaran
6

Hapus satu buku yang kondisinya hilang, lalu hitung ulang isi koleksinya.

mongosh
db.buku.deleteOne({ judul: "Sistem Operasi" })
text Keluaran
{ acknowledged: true, deletedCount: 1 }

Penghapusan pada MongoDB bekerja pada tingkat dokumen, yaitu seluruh isi dokumen hilang sekali gus dan tidak ada cara membuang sebagian field dengan deleteOne. Pengubahan sebagian field merupakan ranah operator update, sedangkan pembuangan dokumen utuh merupakan ranah metode ini. Pemisahan keduanya membuat maksud setiap perintah tulis mudah dibaca kembali dari bentuknya.

mongosh
db.buku.countDocuments()
text Keluaran
5

Nilai deletedCount: 1 menegaskan satu dokumen telah terhapus, sedangkan hasil penghitungan berikutnya turun menjadi lima. Satu pemanggilan deleteOne tidak pernah menghapus lebih dari satu dokumen, walaupun filternya cocok dengan banyak dokumen sekaligus. Perilaku itulah yang dibedah pada bagian berikutnya.

Filter yang cocok lebih dari satu dokumen#

Filter pada deleteOne boleh cocok dengan beberapa dokumen sekaligus. Dalam keadaan itu, satu-satunya dokumen yang terhapus adalah dokumen pertama menurut natural order, yaitu urutan penyimpanan internal koleksi. Pada koleksi sederhana di satu server, urutan tersebut praktis mengikuti urutan penyisipan, tetapi MongoDB tidak menetapkannya sebagai jaminan.

Hasil kembalian deleteOne pada filter yang luas tetap berupa deletedCount: 1, sama seperti penghapusan dengan filter unik. Nilai tersebut tidak memberi petunjuk dokumen mana yang benar-benar terhapus. Kepastian hanya dapat diperoleh melalui pembacaan ulang koleksi, sebagaimana dipraktikkan pada contoh berikut.

mongosh
db.buku.deleteOne({ kondisi: "rusak" })
text Keluaran
{ acknowledged: true, deletedCount: 1 }
mongosh
db.buku.find({ kondisi: "rusak" }, { judul: 1 })
text Keluaran
[
  {
    _id: ObjectId('6ae874dd15c46e1f988de669'),
    judul: 'Statistika Dasar'
  }
]

Hasil pembacaan ulang memperlihatkan sisa kecocokan berupa Statistika Dasar, sehingga dokumen yang terhapus adalah Jaringan Komputer yang disisipkan lebih awal. Ketiadaan kontrol atas dokumen mana yang terhapus menjadi alasan utama untuk menghindari filter yang luas pada deleteOne. Ketika satu dokumen tertentu menjadi sasaran, filter _id memberikan ketepatan karena nilainya unik di dalam koleksi.

Menghapus banyak dokumen dengan deleteMany#

Metode deleteMany menghapus seluruh dokumen yang cocok dengan filter sekaligus, dan hasil kembaliannya merangkum jumlahnya pada deletedCount. Filternya ditulis dengan aturan yang sama seperti filter find, sehingga seluruh operator query dapat dipakai untuk mempersempit sasaran. Data sisa pada koleksi saat ini masih memuat satu buku dengan stok kosong.

mongosh
db.buku.deleteMany({ stok: 0 })
text Keluaran
{ acknowledged: true, deletedCount: 1 }
mongosh
db.buku.find({}, { _id: 0, judul: 1, stok: 1 })
text Keluaran
[
  { judul: 'Dasar Pemrograman', stok: 3 },
  { judul: 'Basis Data Modern', stok: 5 },
  { judul: 'Algoritma Lanjutan', stok: 2 }
]

Hasilnya satu dokumen terhapus karena hanya Statistika Dasar yang berstok nol pada saat perintah dijalankan. Pembacaan sisa koleksi dengan proyeksi menunjukkan tiga buku yang seluruhnya berstok positif. Pola verifikasi seperti ini, yaitu menghapus lalu membaca sisa koleksi, membantu memastikan cakupan filter tidak melebihi niat awal.

Perkiraan cakupan filter juga dapat diperiksa sebelum eksekusi dengan menghitung dokumen yang cocok terlebih dahulu. Pemanggilan countDocuments dengan filter yang sama memberikan jumlah dokumen yang akan terhapus, sehingga angka yang jauh dari dugaan langsung terlihat sebelum perintah destruktifnya berjalan. Pemeriksaan semacam ini murah karena hanya membaca, dan makin berguna ketika filter ditulis dengan operator rentang seperti $lte.

Disiplin penghapusan#

Penghapusan pada MongoDB tidak memiliki kotak konfirmasi maupun mekanisme urungkan bawaan. Dokumen yang sudah terhapus hanya dapat diperoleh kembali dari sumber data lain, misalnya cadangan yang dibuat sebelumnya atau penyisipan ulang manual, sehingga disiplin pada tahap sebelum eksekusi menjadi satu-satunya pengaman yang murah. Disiplin tersebut berupa tiga kebiasaan yang saling melengkapi.

  • Jalankan filter yang sama dengan find atau findOne terlebih dahulu, lalu pastikan dokumen yang muncul persis merupakan sasaran penghapusan.
  • Gunakan _id sebagai filter untuk penghapusan tunggal karena kecocokannya tidak ambigu.
  • Pertimbangkan penghapusan lunak (soft delete), yaitu menandai dokumen dengan field seperti arsip: true alih-alih menghapusnya, apabila data masih mungkin dibutuhkan kembali.

Ketiga kebiasaan itu menuntut kerja ekstra berupa satu perintah pembacaan tambahan, tetapi biayanya jauh lebih kecil daripada data yang hilang karena filter yang keliru. Kebiasaan verifikasi juga menghasilkan kerja yang rapi, karena filter yang telah diuji dengan find mudah dipindahkan ke kode aplikasi tanpa perubahan makna. Perlakuan yang sama berlaku pada operasi tulis lainnya, sehingga pola uji lalu eksekusi dapat dipegang secara konsisten.

Kesalahan umum#

Kesalahan pertama berupa filter yang tidak cocok dengan dokumen mana pun. Perintahnya tetap berhasil dijalankan tanpa pesan error, sedangkan deletedCount yang bernilai 0 menjadi satu-satunya petunjuknya. Situasi ini berbeda dari filter yang salah bentuk, karena filter yang salah bentuk dijawab dengan pesan error.

mongosh
db.buku.deleteOne({ judul: "Buku Fantasi" })
text Keluaran
{ acknowledged: true, deletedCount: 0 }

Nilai deletedCount: 0 pada contoh di atas muncul karena tidak ada buku dengan judul tersebut, misalnya akibat salah ketik, perbedaan huruf kapital, atau tipe nilai yang berbeda dari yang tersimpan. Perlakuan yang tepat adalah memeriksa ulang filter dengan find yang sama sampai dokumen sasarannya muncul, baru perintah penghapusannya dijalankan. Pemeriksaan singkat ini menangkap salah ketik jauh sebelum perintah destruktifnya berjalan.

Kesalahan kedua berupa filter kosong pada deleteMany, yang cocok dengan seluruh dokumen tanpa pengecualian. Koleksi saat ini memuat tiga buku, dan perintah berikut menghabiskan seluruhnya. Tujuan pembahasannya bukan perintahnya sendiri, melainkan akibat yang tidak selalu disadari.

mongosh
db.buku.deleteMany({})
text Keluaran
{ acknowledged: true, deletedCount: 3 }
mongosh
db.buku.countDocuments()
text Keluaran
0

Hasilnya deletedCount: 3 diikuti penghitungan yang bernilai 0, yaitu koleksi yang kosong tetapi masih ada. Koleksi kosong seperti ini tetap tercantum pada daftar koleksi beserta indeksnya, sedangkan metode drop() menghapus koleksi beserta seluruh indeksnya. Kedua operasi itu berbeda tujuan, sehingga pemilihannya harus mengikuti kebutuhan, bukan kebiasaan.

Ringkasan#

  • deleteOne menghapus paling banyak satu dokumen, sedangkan deleteMany menghapus seluruh dokumen yang cocok, dan keduanya melaporkan jumlahnya pada deletedCount.
  • Pada filter berkecocokan banyak, deleteOne menghapus dokumen pertama menurut natural order, sehingga filter _id lebih tepat untuk penghapusan tunggal.
  • Filter yang tidak cocok menghasilkan deletedCount: 0 tanpa pesan error, sehingga verifikasi dengan find menjadi kebiasaan yang wajib.
  • Filter kosong pada deleteMany mengosongkan koleksi tetapi tidak menghapus koleksinya, berbeda dari drop() yang menghapus keduanya.

Referensi#