Tahap $count mengerjakan satu hal dan mengerjakannya dengan sintaks paling ringkas di seluruh pipeline: menghitung document yang sampai padanya, lalu mengganti seluruh aliran dengan satu document berisi angka itu. Kesederhanaan ini menjadikannya alat uji yang pas saat membangun pipeline bertahap — hitung dulu berapa document yang lolos tahap demi tahap, baru susun tahap berikutnya. Chapter ini membedah bentuknya, kesetaraannya dengan $group, dan satu jebakan hasil kosong yang wajib diketahui.
Bentuk Paling Singkat #
Nilai $count adalah string nama field untuk hasilnya. Kita pakai data toko buku yang sudah akrab:
use latihan_agregasi
db.dropDatabase()Output yang Dihasilkan:
switched to db latihan_agregasi
{ ok: 1, dropped: 'latihan_agregasi' }db.buku.insertMany([
{ _id: 1, judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000, kategori: "Fiksi", tag: ["sastra", "novel"], stok: 12, tahun_terbit: 2017, terjual: [ { bulan: "Januari", jumlah: 14 }, { bulan: "Februari", jumlah: 9 }, { bulan: "Maret", jumlah: 11 } ] },
{ _id: 2, judul: "Bumi", penulis: "Tere Liye", harga: 89000, kategori: "Fiksi", tag: ["novel", "fantasi"], stok: 20, tahun_terbit: 2014, terjual: [ { bulan: "Januari", jumlah: 21 }, { bulan: "Februari", jumlah: 17 }, { bulan: "Maret", jumlah: 25 } ] },
{ _id: 3, judul: "Supernova: Ksatria, Puteri, dan Bintang Jatuh", penulis: "Dee Lestari", harga: 95000, kategori: "Fiksi", tag: ["novel", "sains"], stok: 6, tahun_terbit: 2001, terjual: [ { bulan: "Januari", jumlah: 7 }, { bulan: "Februari", jumlah: 5 } ] },
{ _id: 4, judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, kategori: "Nonfiksi", tag: ["filsafat", "pengembangan diri"], stok: 8, tahun_terbit: 2018, terjual: [ { bulan: "Januari", jumlah: 12 }, { bulan: "Februari", jumlah: 15 }, { bulan: "Maret", jumlah: 10 } ] },
{ _id: 5, judul: "Atomic Habits", penulis: "James Clear", harga: 115000, kategori: "Nonfiksi", tag: ["pengembangan diri", "kebiasaan"], stok: 15, tahun_terbit: 2018, terjual: [ { bulan: "Januari", jumlah: 18 }, { bulan: "Februari", jumlah: 22 }, { bulan: "Maret", jumlah: 16 } ] },
{ _id: 6, judul: "Kamus Bahasa Indonesia", penulis: "Badan Bahasa", harga: 55000, kategori: "Referensi", tag: ["referensi", "bahasa"], stok: 30, tahun_terbit: 2016, terjual: [] }
])Output yang Dihasilkan:
{
acknowledged: true,
insertedIds: { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5, '5': 6 }
}db.buku.aggregate([ { $count: "jumlahBuku" } ])Output yang Dihasilkan:
[ { jumlahBuku: 6 } ]Enam document masuk, satu document keluar — field jumlahBuku bernilai 6. Ditempatkan setelah tahap penyaring, $count melaporkan jumlah yang lolos:
db.buku.aggregate([ { $match: { kategori: "Fiksi" } }, { $count: "jumlahFiksi" } ])Output yang Dihasilkan:
[ { jumlahFiksi: 3 } ]Setara dengan $group #
$count pada dasarnya adalah singkatan. Pipeline berikut mengerjakan pekerjaan yang persis sama dengan tiga tahap lebih banyak:
db.buku.aggregate([ { $group: { _id: null, n: { $sum: 1 } } }, { $project: { _id: 0, n: 1 } } ])Output yang Dihasilkan:
[ { n: 6 } ]$group dengan _id: null melipat seluruh document menjadi satu kelompok, { $sum: 1 } menghitung anggotanya, dan $project membuang _id: null agar bentuknya sama dengan hasil $count. Ketika yang dibutuhkan hanya angka, singkatan ini jelas lebih mudah dibaca; bentuk $group baru bernilai saat hasil hitungan ingin disandingkan angka lain — misalnya totalStok berdampingan dengan jumlah buku.
Posisi Menentukan Apa yang Dihitung #
Karena $count menghitung document yang mengalir kepadanya, posisinya menentukan objek yang dihitung. Ditempatkan setelah $unwind, ia menghitung pecahan array; setelah $group, ia menghitung jumlah kelompok:
db.buku.aggregate([ { $unwind: "$tag" }, { $count: "jumlahTagDocument" } ])
db.buku.aggregate([ { $group: { _id: "$kategori" } }, { $count: "jumlahKategori" } ])Output yang Dihasilkan:
[ { jumlahTagDocument: 12 } ]
[ { jumlahKategori: 3 } ]Enam buku dengan dua tag per buku menjadi dua belas document pecahan — dan tiga kategori menjadi tiga kelompok. Perbedaan 12 lawan 3 pada collection yang sama menegaskan pesan Chapter sebelumnya: baca pipeline dari tahap sebelum $count untuk tahu apa yang persisnya dihitung.
Hasil Kosong Bukan Nol #
Inilah jebakan terpenting chapter ini. Ketika tidak ada satu pun document yang sampai ke $count, tahap ini tidak menghasilkan document { jumlah: 0 } — hasilnya kosong:
db.buku.aggregate([ { $match: { kategori: "Komik" } }, { $count: "jumlah" } ]).toArray()
db.buku.countDocuments({ kategori: "Komik" })Output yang Dihasilkan:
[]
0Tidak ada buku berkategori Komik, sehingga $match melewatkan nol document, dan $count — yang tidak menerima apa pun untuk dihitung — tidak mengeluarkan apa pun. countDocuments() pada baris kedua menghadapi situasi yang sama tetapi melaporkannya sebagai angka 0. Perbedaan ini berdampak nyata di kode aplikasi: hasil[0].jumlah akan error pada hasil kosong $count, sementara countDocuments() selalu bisa langsung dibandingkan dengan angka.
$count vs countDocuments #
| Aspek | $count (tahap) | countDocuments() |
|---|---|---|
| Bentuk | Tahap pipeline, {"$count": "nama"} | Method collection |
| Hasil input kosong | Tidak ada document | 0 |
| Bisa di tengah pipeline | ✔ — setelah $unwind, $group, dsb. | ✖ — hanya filter pada collection asli |
| Cocok untuk | Verifikasi jumlah di tengah pipeline | Jawaban cepat “berapa yang cocok filter ini” |
Rangkuman #
{ $count: "namaField" }menghitung document yang mengalir ke tahapnya dan menghasilkan satu document berisi angka.- Setara penuh dengan
$group_id: null+$sum: 1+$project— versi singkatnya. - Posisi menentukan objek hitungan: setelah
$unwindmenghitung pecahan array, setelah$groupmenghitung kelompok. - Input kosong menghasilkan kosong, bukan nol — berbeda dari
countDocuments()yang selalu mengembalikan angka.