Tidak semua pertanyaan butuh daftar. “Apakah buku dengan judul ini sudah ada di katalog?” atau “berapa stok Laut Bercerita?” hanya membutuhkan satu document — menarik seluruh hasil dengan find() untuk lalu mengabaikan sisanya adalah pemborosan. Untuk kebutuhan seperti itu MongoDB menyediakan findOne(): mengembalikan document pertama yang cocok, atau null bila tidak ada sama sekali. Chapter ini membahas perilaku keduanya, pola cek keberadaan, dan proyeksi untuk memangkas field yang diambil.
Peta materi Chapter ini:
findOne()dengan dan tanpa filter; document pertama yang menang.- Nilai
nullsaat tidak ada yang cocok, dan cara menanganinya di JavaScript. - Pola cek keberadaan document.
- Proyeksi ringan: memilih field yang ikut diambil.
Document Pertama yang Menang #
Bentuk panggilannya sejajar dengan find(): db.<collection>.findOne(<filter>). Bedanya ada di nilai balik — satu document, bukan cursor. Siapkan katalog seperti biasa:
use latihan_crud
db.buku.drop()Output yang Dihasilkan:
switched to db latihan_crud
truedb.buku.insertMany([
{ judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000, stok: 12, kategori: "fiksi", tag: ["fiksi", "sastra"], rating: 4.7 },
{ judul: "Bumi", penulis: "Tere Liye", harga: 89000, stok: 25, kategori: "fiksi", tag: ["fiksi", "remaja"], rating: 4.5 },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, stok: 18, kategori: "nonfiksi", tag: ["filsafat", "pengembangan diri"], rating: 4.8 },
{ judul: "Atomic Habits", penulis: "James Clear", harga: 115000, stok: 30, kategori: "nonfiksi", tag: ["pengembangan diri", "terjemahan"], rating: 4.6 },
{ judul: "Rumah Kaca", penulis: "Tere Liye", harga: 72000, stok: 9, kategori: "fiksi", tag: ["fiksi", "remaja"], rating: 4.3 },
{ judul: "Sang Pemimpi", penulis: "Andrea Hirata", harga: 65000, stok: 0, kategori: "fiksi", tag: ["fiksi", "sastra"], rating: 4.6 }
])Output yang Dihasilkan:
{
acknowledged: true,
insertedIds: {
'0': ObjectId('6ad386e52bade0cbd448bac2'),
'1': ObjectId('6ad386e52bade0cbd448bac3'),
'2': ObjectId('6ad386e52bade0cbd448bac4'),
'3': ObjectId('6ad386e52bade0cbd448bac5'),
'4': ObjectId('6ad386e52bade0cbd448bac6'),
'5': ObjectId('6ad386e52bade0cbd448bac7')
}
}Tanpa filter, findOne() mengembalikan document pertama collection:
db.buku.findOne()Output yang Dihasilkan:
{
_id: ObjectId('6ad386e52bade0cbd448bac2'),
judul: 'Laut Bercerita',
penulis: 'Leila S. Chudori',
harga: 98000,
stok: 12,
kategori: 'fiksi',
tag: [ 'fiksi', 'sastra' ],
rating: 4.7
}Yang kembali adalah Laut Bercerita — document yang paling dulu tersimpan. Sekarang filter dengan penulis yang punya dua karya:
db.buku.findOne({ penulis: "Tere Liye" })Output yang Dihasilkan:
{
_id: ObjectId('6ad386e52bade0cbd448bac3'),
judul: 'Bumi',
penulis: 'Tere Liye',
harga: 89000,
stok: 25,
kategori: 'fiksi',
tag: [ 'fiksi', 'remaja' ],
rating: 4.5
}Tere Liye menulis Bumi dan Rumah Kaca, tetapi yang kembali hanya Bumi. findOne() berhenti di kecocokan pertama sesuai urutan penyimpanan; document berikutnya yang sama-sama cocok tidak pernah diambil. Perilaku ini setara dengan find() yang dibatasi satu hasil — dan di situlah letak penghematannya: server berhenti memindai begitu satu document memenuhi filter, bukan menyiapkan seluruh hasil.
Konsekuensi praktisnya: findOne() paling tepat dipakai pada filter yang memang ditujukan unik — _id, ISBN, atau email. Bila filter bisa cocok untuk banyak document dan urutannya penting, hasil findOne() tanpa pengurutan tidak bisa diandalkan — MongoDB tidak menjamin urutan hasil query kecuali kita memakai sort().
null dan Cara Membacanya #
Saat filter tidak cocok dengan satu document pun, findOne() tidak diam seperti find() — method ini mengembalikan nilai null secara eksplisit:
db.buku.findOne({ judul: "Ensiklopedia Galaksi" })Output yang Dihasilkan:
nullnull adalah jawaban yang jujur dan mudah diuji di JavaScript. Namun ada satu jebakan klasik: mengakses field pada hasil null langsung melempar galat.
const hasil = db.buku.findOne({ judul: "Ensiklopedia Galaksi" })
hasil.judulOutput yang Dihasilkan:
Uncaught
TypeError: Cannot read properties of null (reading 'judul')Pesan TypeError: Cannot read properties of null muncul karena kita meminta field judul dari sesuatu yang tidak ada. Kuncinya: periksa dulu, baru akses. Pola if menuntaskan hal ini sekaligus menjadi dasar cek keberadaan:
if (hasil) {
print("Ditemukan, stok: " + hasil.stok)
} else {
print("Buku tidak terdaftar di katalog")
}Output yang Dihasilkan:
Buku tidak terdaftar di katalogDi JavaScript, null bernilai falsy sehingga blok else yang berjalan. Dua pola ini — simpan hasil di variabel, lalu uji sebelum mengakses — adalah kebiasaan wajib setiap kali hasil query bisa saja kosong. Pola serupa berlaku di semua driver: PyMongo mengembalikan None, dan driver Node.js mengembalikan null, jadi pemeriksaan serupa tetap diperlukan di aplikasi nyata.
Proyeksi Ringan #
Sering kali kita hanya butuh satu-dua field, misalnya harga untuk halaman produk. Argumen kedua findOne() — dan find() juga — menerima proyeksi: daftar field yang ikut diambil, ditulis { field: 1 }:
db.buku.findOne({ judul: "Bumi" }, { judul: 1, harga: 1 })Output yang Dihasilkan:
{
_id: ObjectId('6ad386e52bade0cbd448bac3'),
judul: 'Bumi',
harga: 89000
}Hanya _id, judul, dan harga yang datang dari server. Field _id selalu ikut secara bawaan; bila ingin meniadakannya, tulis eksplisit { _id: 0 }:
db.buku.findOne({ judul: "Bumi" }, { _id: 0, judul: 1, harga: 1 })Output yang Dihasilkan:
{ judul: 'Bumi', harga: 89000 }Bentuk { field: 1 } disebut proyeksi inclusion — menyebutkan field yang diikutsertakan. Lawannya, { field: 0 } menyebutkan field yang dibuang, dan hanya _id yang boleh digabung dengan bentuk inclusion; mencampur keduanya untuk field lain ditolak server. Pilih inclusion saat field yang dibutuhkan sedikit, pilih exclusion saat field yang dibuang sedikit.
Proyeksi bukan sekadar kerapian tampilan: field yang tidak diminta tidak pernah meninggalkan server, sehingga data yang besar — deskripsi panjang, daftar ulasan — tidak ikut membebani jaringan. Di Chapter Query Filters ke depannya kita memakai proyeksi ini terus-menerus agar contoh tetap ringkas.
Sebagai penutup, bersihkan database latihan:
db.dropDatabase()Output yang Dihasilkan:
{ ok: 1, dropped: 'latihan_crud' }Rangkuman #
findOne(<filter>)mengembalikan document pertama yang cocok sesuai urutan penyimpanan, bukan seluruh hasil.- Tanpa kecocokan, nilai baliknya
null— berbeda darifind()yang tidak mencetak apa-apa. - Akses field pada hasil
nullmelemparTypeError; simpan hasil di variabel dan uji denganifsebelum mengakses. - Pola
if (hasil)sekaligus menjadi cara cek keberadaan document yang paling sederhana. - Argumen kedua adalah proyeksi
{ field: 1 };_idikut terbawa kecuali dikecualikan dengan{ _id: 0 }.
Satu document sudah bisa diambil dengan presisi. Chapter berikutnya membangun kosakata filter secara sistematis — dimulai dari kesamaan field paling sederhana.