Belajar MongoDB - Advanced Query Filters & Operators
Episode 5 of 21

Belajar MongoDB - Advanced Query Filters & Operators

Memperdalam kemampuan query dengan operator perbandingan, logika, elemen, dan array; menguasai sorting, limit, dan skip; serta membedah offset-based pagination versus cursor-based pagination untuk aplikasi berskala.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 3 dan 4 kalian sudah menulis query sederhana: filter berdasarkan kesetaraan ({ name: "Sneaker" }) dan update dengan operator. Tapi aplikasi dunia nyata jarang sesederhana itu. Pertanyaan seperti "tampilkan produk antara 100 ribu dan 500 ribu", "cari user yang aktif ATAU punya role mentor", atau "cari order yang semua statusnya paid" butuh operator yang jauh lebih kaya.

Episode 5 adalah gudang senjata query. Roadmap-nya: pertama operator perbandingan, kedua operator logika, ketiga operator elemen, keempat operator array, dan kelima sorting serta pagination. Akhir episode, kalian akan bisa menjawab hampir semua kebutuhan filter aplikasi dengan satu bahasa query yang ekspresif.

Comparison Operators

Operator perbandingan adalah yang paling dasar dan paling sering dipakai. Perhatikan bentuknya: field di sebelah kiri, operator di dalam object di sebelah kanan:

OperatorArtiContoh
$eqSama dengan{ price: { $eq: 150000 } }
$neTidak sama dengan{ role: { $ne: "admin" } }
$gtLebih besar{ price: { $gt: 150000 } }
$gteLebih besar atau sama{ stock: { $gte: 5 } }
$ltLebih kecil{ age: { $lt: 30 } }
$lteLebih kecil atau sama{ age: { $lte: 30 } }
$inSalah satu dari daftar{ category: { $in: ["elektronik", "fashion"] } }
$ninBukan salah satu dari daftar{ category: { $nin: ["makanan"] } }
Kombinasi comparison operators
db.products.find({
  category: { $in: ["elektronik", "fashion"] },
  price: { $gte: 100000, $lte: 1000000 }
})

Perhatikan contoh kedua: field price menerima beberapa operator sekaligus dalam satu object — artinya semua kondisi harus terpenuhi. Ini jauh lebih ringkas daripada menulis dua filter terpisah.

Logical Operators

Operator logika mengatur bagaimana kondisi digabungkan:

OperatorArti
$andSemua kondisi harus benar (default implisit saat menulis beberapa field)
$orMinimal satu kondisi benar
$notMembalik hasil kondisi
$norSemua kondisi harus salah

Contoh paling berguna adalah $or — mencari dokumen yang cocok dengan salah satu kondisi:

Menggabungkan kondisi dengan $or dan $and
db.users.find({
  $or: [
    { role: "mentor" },
    { isActive: true }
  ],
  $and: [
    { age: { $gte: 18 } },
    { age: { $lte: 40 } }
  ]
})

Info

Penting diketahui: saat kalian menulis beberapa field tanpa operator logika eksplisit, MongoDB menggabungkannya dengan $and secara implisit. Jadi { price: { $gt: 100 }, category: "elektronik" } sama artinya dengan menulis { $and: [{ price: { $gt: 100 } }, { category: "elektronik" }] }. Gunakan bentuk eksplisit saat butuh kejelasan atau ada kondisi yang memakai field yang sama.

Element Operators

Karena schema MongoDB fleksibel, tidak semua dokumen dalam satu collection memiliki field yang sama. Dua operator elemen membantu menangani situasi ini:

  • $exists — memeriksa apakah field ada di dokumen (tidak peduli nilainya apa).
  • $type — memeriksa tipe BSON field.
Cek keberadaan dan tipe field
db.products.find({ specs: { $exists: true } })
 
db.products.find({ price: { $type: "decimal" } })

Query pertama menemukan semua produk yang punya field specs. Query kedua menemukan produk yang harga tersimpan sebagai tipe decimal — berguna untuk menemukan data dengan tipe salah yang masuk di masa lalu.

Array Query Operators

Operasi array adalah area paling membedakan MongoDB dari RDBMS. Saat query terhadap field array, MongoDB memiliki perilaku default dan tiga operator khusus:

  • Matching terhadap array: find({ tags: "mongodb" }) cocok jika array mengandung elemen tersebut.
  • $all — array harus mengandung semua elemen yang disebutkan.
  • $elemMatch — setidaknya satu elemen array memenuhi beberapa kondisi sekaligus.
  • $size — panjang array sama dengan nilai yang diberikan.
Contoh array query operators
db.products.find({ tags: { $all: ["best-seller", "baru"] } })
 
db.orders.find({
  items: {
    $elemMatch: { product: "laptop", qty: { $gte: 2 } }
  }
})
 
db.orders.find({ items: { $size: 3 } })

Contoh $elemMatch paling penting: ia mencari order yang memiliki satu item bernama laptop sekaligus qty-nya minimal 2 dalam elemen yang sama di array. Tanpa $elemMatch, kondisi { "items.product": "laptop", "items.qty": { $gte: 2 } } bisa cocok dengan dua elemen berbeda — perilaku yang sering membingungkan.

Sorting, Limiting, dan Skipping

Sorting

Urutkan hasil dengan .sort(). Nilai 1 berarti ascending (kecil ke besar), -1 berarti descending (besar ke kecil):

Sorting ascending dan descending
db.products.find({}).sort({ price: 1 })
 
db.products.find({}).sort({ price: -1, createdAt: -1 })

Limiting dan Skipping

.limit(n) membatasi jumlah hasil; .skip(n) melompati n dokumen pertama:

Menggabungkan sort, limit, dan skip
db.products.find({})
  .sort({ price: -1 })
  .limit(10)
  .skip(20)

Query di atas mengambil halaman ketiga (dengan asumsi 10 item per halaman) dari produk termahal ke termurah. Inilah dasar offset-based pagination.

Pagination: Offset vs Cursor

Offset-Based Pagination

Pola di atas (skip + limit) adalah offset-based pagination — paling sederhana, cocok untuk halaman kecil. Tapi ia punya kelemahan mendasar: .skip() tetap memindai dokumen yang dilewati. Saat dataset membesar (misal skip 100.000), query melambat drastis. Belum lagi jika ada data baru masuk di tengah navigasi, hasil bisa "loncat" dan halaman berduplikasi.

Cursor-Based Pagination

Untuk dataset besar atau data yang terus berubah, gunakan cursor-based pagination: simpan nilai unik terakhir dari halaman sebelumnya, lalu filter berdasarkan nilai itu. Karena memakai index, performanya tetap cepat berapapun kedalaman halaman:

Cursor-based pagination dengan nilai terakhir
db.products.find({
  $or: [
    { price: { $lt: 150000 } },
    { price: 150000, _id: { $gt: ObjectId("66xxxxxxxxxxxxxxxxxxxxxxxx") } }
  ]
}).sort({ price: -1, _id: -1 }).limit(10)

Pola $or di atas mengambil 10 produk dengan harga kurang dari 150 ribu, atau harga tepat 150 ribu dengan _id lebih besar dari produk terakhir yang dilihat — komposisi (price, _id) yang terurut rapi menjamin tidak ada data terlewat atau duplikat.

Warning

Pagination besar (deep pagination) dengan skip pada collection jutaan dokumen adalah salah satu penyebab paling umum query lambat di produksi. Jika kalian melihat skip yang besar (ribuan ke atas) sering dipanggil, pertimbangkan berpindah ke cursor-based pagination — atau kombinasikan dengan filter temporal (misal "ambil order bulan ini") untuk mempersempit cakupan.

Penutup

Pada episode 5 ini kalian telah memperluas kemampuan query secara signifikan: operator perbandingan $gt, $gte, $lt, $lte, $in, $nin, dan $ne; operator logika $and, $or, $not, dan $nor; operator elemen $exists dan $type; operator array $all, $elemMatch, dan $size; serta sorting, limit, skip, dan dua pendekatan pagination — offset-based dan cursor-based.

Inti yang harus dibawa pulang:

  • Filter field ganda digabung dengan $and implisit; gunakan $or untuk alternatif.
  • $elemMatch mencocokkan kondisi pada elemen array yang sama — hindari jebakan query array biasa.
  • $exists dan $type sangat berguna di schema yang fleksibel.
  • .sort().limit().skip() adalah dasar pagination sederhana.
  • Untuk dataset besar, cursor-based pagination jauh lebih cepat dan konsisten.

Di episode 6 berikutnya kita naik level dari "bisa query" ke "merancang data dengan benar": Schema Design Patterns & Best Practices. Kalian akan memahami bahwa flexible schema bukan berarti tanpa desain, mempelajari prinsip data locality, serta mengenali anti-pattern yang harus dihindari seperti massive arrays dan excessive nesting. Sampai jumpa di episode 6!

Belajar MongoDB - Advanced Query Filters & Operators | Belajar MongoDB