“Ada berapa buku fiksi di katalog?”, “berapa produk di bawah Rp100.000?”, “total item untuk badge pada ikon keranjang” — pertanyaan hitungan muncul di hampir semua fitur. MongoDB menyediakan dua method penghitungan dengan karakter yang berbeda: countDocuments() yang menghitung dengan benar melalui filter, dan estimatedDocumentCount() yang membaca angka cepat dari metadata collection. Memilih yang tepat berarti memilih antara akurasi dan kecepatan. Chapter ini menguji keduanya pada data yang sama.

Peta materi Chapter ini:

  • countDocuments() dengan filter kosong dan filter biasa.
  • estimatedDocumentCount() dan asal-usul angkanya.
  • Kapan memakai yang mana.

countDocuments dengan Filter #

Siapkan katalog — Kamus Bahasa Indonesia sengaja tanpa rating untuk melihat perilaku penghitungan pada field yang hilang:

js
use latihan_query
db.buku.drop()

Output yang Dihasilkan:

text
switched to db latihan_query
true
js
db.buku.insertMany([
  { judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000, stok: 12, kategori: "fiksi", rating: 4.7 },
  { judul: "Bumi", penulis: "Tere Liye", harga: 89000, stok: 25, kategori: "fiksi", rating: 4.5 },
  { judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, stok: 18, kategori: "nonfiksi", rating: 4.8 },
  { judul: "Atomic Habits", penulis: "James Clear", harga: 115000, stok: 30, kategori: "nonfiksi", rating: 4.6 },
  { judul: "Rumah Kaca", penulis: "Tere Liye", harga: 72000, stok: 9, kategori: "fiksi", rating: 4.3 },
  { judul: "Kamus Bahasa Indonesia", penulis: "Badan Bahasa", harga: 55000, stok: 4, kategori: "referensi" }
])

Output yang Dihasilkan:

text
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('6ad39000f48b50514c3d21e6'),
    '1': ObjectId('6ad39000f48b50514c3d21e7'),
    '2': ObjectId('6ad39000f48b50514c3d21e8'),
    '3': ObjectId('6ad39000f48b50514c3d21e9'),
    '4': ObjectId('6ad39000f48b50514c3d21ea'),
    '5': ObjectId('6ad39000f48b50514c3d21eb')
  }
}

countDocuments(filter) menerima filter yang sama persis dengan find() dan mengembalikan jumlah document yang cocok — tanpa mengirim isi document-nya:

js
db.buku.countDocuments({})
db.buku.countDocuments({ kategori: "fiksi" })
db.buku.countDocuments({ harga: { $gte: 90000 } })

Output yang Dihasilkan:

text
6
3
2

Mari kita bedah tiga angka itu:

  1. countDocuments({}): filter kosong mencocokkan semua document, hasilnya total isi collection — 6.
  2. { kategori: "fiksi" }: tiga buku fiksi (Laut Bercerita, Bumi, Rumah Kaca) memenuhi syarat.
  3. { harga: { $gte: 90000 } }: operator perbandingan bekerja seperti biasa; dua buku harganya 98000 dan 115000.

Filter juga mengikuti aturan field yang hilang. Query berdasarkan rating tidak menghitung document tanpa field tersebut:

js
db.buku.countDocuments({ rating: { $gte: 4.5 } })
db.buku.countDocuments({ rating: { $lt: 4.5 } })

Output yang Dihasilkan:

text
4
1

Empat buku ber-rating tinggi, satu buku di bawah 4.5, dan Kamus Bahasa Indonesia tidak masuk hitungan mana pun karena field rating-nya tidak ada. Perilaku “missing tidak dicocokkan” ini dibedah tuntas di Chapter Null dan Missing Fields.

estimatedDocumentCount: Angka dari Metadata #

Method kedua tidak menerima filter sama sekali:

js
db.buku.estimatedDocumentCount()

Output yang Dihasilkan:

text
6

Angkanya sama — 6 — tetapi jalannya berbeda. estimatedDocumentCount() tidak membaca document; ia membaca statistik collection yang selalu diperbarui oleh mesin penyimpanan. Akibatnya method ini nyaris instan pada collection berapa pun ukurannya, sementara countDocuments({}) pada collection raksasa tetap harus memindai seluruh data (atau index yang tersedia).

Perbedaan karakter keduanya:

AspekcountDocuments(filter)estimatedDocumentCount()
Sumber angkamencocokkan document lewat querymetadata collection
Dukungan filterya, filter lengkaptidak ada
Kecepatanbergantung ukuran hasil dan indexnyaris konstan
Akurasipasti untuk snapshot dataestimasi

Kapan Memakai yang Mana #

Aturan praktisnya sederhana. Butuh angka yang bergantung pada isi data — per kategori, per rentang harga, hasil filter pencarian — satu-satunya pilihan adalah countDocuments(). Butuh total kasar seluruh collection tanpa filter — misalnya teks “kurang lebih 2,4 juta produk tersedia” di halaman utama, atau indikator ukuran di dashboard monitoring — estimatedDocumentCount() jauh lebih murah.

Perlu dicatat juga: countDocuments() tetap sebuah query. Filter yang selektif di collection besar akan lambat tanpa index yang mendukung — topik yang kita mulai bahas di Chapter Dasar Performa Query dan diperdalam di Section Indexing.

Rangkuman #

  • countDocuments(filter) menghitung document yang cocok dengan filter find() biasa; countDocuments({}) menghitung seluruh collection.
  • Document tanpa field yang difilter tidak ikut terhitung.
  • estimatedDocumentCount() membaca metadata collection: super cepat, tanpa filter, tapi berupa estimasi.
  • Gunakan countDocuments() untuk angka berfilter dan angka yang kritis; gunakan estimasi hanya untuk total kasar.