Halaman katalog toko buku hampir tidak pernah menampilkan semua field: pengunjung cukup melihat judul dan harga, admin butuh urutan penjualan, dan pencarian harus menyaring rentang harga. Di mongosh kita sudah menulis filter dan projection sebagai document — dari JavaScript, keduanya tetap berbentuk object biasa yang dikirim sebagai argumen method find(). Perbedaannya hanya rumahnya: object literal JavaScript menggantikan document mongosh. Chapter ini memetakan pola filter, projection, dan rantai sort/limit/skip pada collection buku dengan field bersarang penerbit.
Filter Adalah Object Biasa #
Method find() menerima query document — object JavaScript yang isinya field beserta syaratnya. Karena driver mengirim object itu sebagai BSON, seluruh operator query yang kita kenal bekerja tanpa perubahan:
| Kebutuhan | Bentuk filter |
|---|---|
| Persamaan | { judul: "Bumi Manusia" } |
| Perbandingan | { harga: { $gte: 100000 } } |
| Beberapa nilai | { tags: { $in: ["fiksi", "sejarah"] } } |
| Field bersarang | { "penerbit.kota": "Yogyakarta" } |
| Kombinasi ATAU | { $or: [{ penulis: "James Clear" }, { harga: { $lt: 95000 } }] } |
Dua perilaku perlu diingat kembali. Field bertipe array cocok dengan nilai tunggal — { tags: "fiksi" } menemukan setiap document yang array tags-nya memuat "fiksi". Dan penulisan "penerbit.kota" memakai dot notation untuk menjangkau field di dalam object bersarang; tanda kutip wajib agar JavaScript membacanya sebagai satu nama field, bukan ekspresi property.
Projection dan Dot Notation dalam Praktik #
Projection diberikan lewat opsi projection — bukan argumen kedua find() seperti di mongosh. File berikut menanam lima judul lengkap dengan penerbit bersarang, lalu mencoba lima pola query sekaligus:
// filter-proyeksi.js — filter operator, projection, dan dot notation
// Jalankan: MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node filter-proyeksi.js
const { MongoClient } = require("mongodb")
const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/?directConnection=true"
async function main() {
const client = new MongoClient(uri)
await client.connect()
const katalog = client.db("latihan_js").collection("buku")
await katalog.drop().catch(() => {})
await katalog.insertMany([
{ judul: "Laskar Pelangi", penulis: "Andrea Hirata", harga: 95000, terjual: 132, penerbit: { nama: "Bentang Pustaka", kota: "Yogyakarta" }, tags: ["fiksi", "remaja"] },
{ judul: "Bumi Manusia", penulis: "Pramoedya A. Toer", harga: 110000, terjual: 205, penerbit: { nama: "Hasta Mitra", kota: "Jakarta" }, tags: ["fiksi", "sejarah"] },
{ judul: "Atomic Habits", penulis: "James Clear", harga: 125000, terjual: 318, penerbit: { nama: "Gramedia", kota: "Jakarta" }, tags: ["pengembangan diri"] },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 90000, terjual: 276, penerbit: { nama: "Kompas", kota: "Jakarta" }, tags: ["pengembangan diri", "filsafat"] },
{ judul: "Cantik Itu Luka", penulis: "Eka Kurniawan", harga: 105000, terjual: 98, penerbit: { nama: "Gramedia", kota: "Jakarta" }, tags: ["fiksi", "sejarah"] },
])
const proyeksi = { projection: { _id: 0, judul: 1, harga: 1 } }
// 1. Operator perbandingan pada satu field
const mahal = await katalog.find({ harga: { $gte: 100000 } }, proyeksi).toArray()
console.log("harga >= 100000 :", mahal)
// 2. Dot notation untuk field bersarang
const gramedia = await katalog.find({ "penerbit.nama": "Gramedia" }, proyeksi).toArray()
console.log("penerbit Gramedia:", gramedia)
// 3. Array field cocok dengan nilai tunggal, atau $in untuk beberapa nilai
const bertagFiksi = await katalog.find({ tags: "fiksi" }, { projection: { _id: 0, judul: 1 } }).toArray()
console.log("tags berisi fiksi :", bertagFiksi)
const bertagSejarah = await katalog.find({ tags: { $in: ["sejarah"] } }, { projection: { _id: 0, judul: 1 } }).toArray()
console.log("tags $in sejarah :", bertagSejarah)
// 4. $or menggabungkan beberapa kemungkinan
const murahAtauClear = await katalog.find(
{ $or: [{ penulis: "James Clear" }, { harga: { $lt: 95000 } }] },
proyeksi
).toArray()
console.log("$or penulis/harga :", murahAtauClear)
await client.close()
}
main().catch(err => {
console.error("GAGAL:", err.name, "-", err.message)
process.exit(1)
})MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node filter-proyeksi.jsOutput yang Dihasilkan:
harga >= 100000 : [
{ judul: 'Bumi Manusia', harga: 110000 },
{ judul: 'Atomic Habits', harga: 125000 },
{ judul: 'Cantik Itu Luka', harga: 105000 }
]
penerbit Gramedia: [
{ judul: 'Atomic Habits', harga: 125000 },
{ judul: 'Cantik Itu Luka', harga: 105000 }
]
tags berisi fiksi : [
{ judul: 'Laskar Pelangi' },
{ judul: 'Bumi Manusia' },
{ judul: 'Cantik Itu Luka' }
]
tags $in sejarah : [ { judul: 'Bumi Manusia' }, { judul: 'Cantik Itu Luka' } ]
$or penulis/harga : [
{ judul: 'Atomic Habits', harga: 125000 },
{ judul: 'Filosofi Teras', harga: 90000 }
]Mari kita bedah baris-barisnya: const proyeksi = { projection: { _id: 0, judul: 1, harga: 1 } } menyiapkan opsi proyeksi sekali lalu dipakai berulang — bentuk { _id: 0, judul: 1, harga: 1 } adalah inclusion (hanya judul dan harga) dengan satu pengecualian: _id yang secara bawaan selalu ikut dinyalakan bersama inclusion. Filter "penerbit.nama": "Gramedia" menunjukkan dot notation menembus satu lapis object; hasilnya dua judul dari Gramedia. Baris tags: "fiksi" dan tags: { $in: ["sejarah"] } memperlihatkan dua cara menyaring array — nilai tunggal cukup ditulis langsung, beberapa pilihan memakai $in. Terakhir, $or menerima array berisi object filter lengkap, dan document cukup cocok dengan salah satunya.
Menyusun Urutan dengan sort, limit, skip #
find() mengembalikan FindCursor yang belum mengambil data apa pun. Method sort(), limit(), dan skip() dirantai pada cursor sebelum hasil diambil — tiap method mengembalikan cursor itu sendiri sehingga bisa ditulis berurutan:
// urut-batasi-lewati.js — rantai cursor: sort, limit, skip
// Jalankan SETELAH filter-proyeksi.js (memakai data yang ditanamkan file itu):
// MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node urut-batasi-lewati.js
const { MongoClient } = require("mongodb")
const uri = process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/?directConnection=true"
async function main() {
const client = new MongoClient(uri)
await client.connect()
const katalog = client.db("latihan_js").collection("buku")
const proyeksi = { projection: { _id: 0, judul: 1, terjual: 1 } }
// sort + limit: tiga buku dengan penjualan tertinggi
const terlaris = await katalog.find({}, proyeksi).sort({ terjual: -1 }).limit(3).toArray()
console.log("3 terlaris :", terlaris)
// skip + limit: "halaman 2" berisi data setelah tiga teratas
const halaman2 = await katalog.find({}, proyeksi).sort({ terjual: -1 }).skip(3).limit(3).toArray()
console.log("halaman 2 :", halaman2)
// sort dua kunci: kota penerbit naik, lalu harga turun (dot notation di sort)
const perKota = await katalog.find({}, { projection: { _id: 0, judul: 1, harga: 1 } })
.sort({ "penerbit.kota": 1, harga: -1 })
.toArray()
console.log("per kota :", perKota)
await client.close()
}
main().catch(err => {
console.error("GAGAL:", err.name, "-", err.message)
process.exit(1)
})MONGODB_URI="mongodb://127.0.0.1:27017/?directConnection=true" node urut-batasi-lewati.jsOutput yang Dihasilkan:
3 terlaris : [
{ judul: 'Atomic Habits', terjual: 318 },
{ judul: 'Filosofi Teras', terjual: 276 },
{ judul: 'Bumi Manusia', terjual: 205 }
]
halaman 2 : [
{ judul: 'Laskar Pelangi', terjual: 132 },
{ judul: 'Cantik Itu Luka', terjual: 98 }
]
per kota : [
{ judul: 'Atomic Habits', harga: 125000 },
{ judul: 'Bumi Manusia', harga: 110000 },
{ judul: 'Cantik Itu Luka', harga: 105000 },
{ judul: 'Filosofi Teras', harga: 90000 },
{ judul: 'Laskar Pelangi', harga: 95000 }
]Urutan rantai tidak mengubah hasil untuk sort → limit → skip pada satu query, tetapi kebiasaan menulis sesuai urutan logika (urutkan, batasi, lewati) membuat maksud kode mudah dibaca. Nilai -1 pada sort({ terjual: -1 }) berarti menurun; 1 berarti menaik. Pada sort terakhir, dot notation dipakai untuk kunci pertama ("penerbit.kota" naik) dan kunci kedua (harga turun) hanya berlaku untuk document yang seri pada kunci pertama — terlihat pada empat judul Jakarta yang tersusun dari harga tertinggi.
Rangkuman #
- Filter dan projection dikirim sebagai object JavaScript; seluruh operator query mongosh (
$gte,$in,$or) berlaku tanpa perubahan. - Projection ditulis pada opsi
projection; inclusion{ judul: 1, harga: 1 }plus_id: 0untuk memangkas field bawaan itu. - Dot notation (
"penerbit.kota") menjangkau field bersarang di filter, projection, dan sort. sort(),limit(),skip()dirantai padaFindCursorsebelumtoArray()— skip-based pagination sederhana tetapi makin mahal pada halaman yang dalam.