Kotak pencarian toko buku menerima kata apa pun — “bumi”, “terbiasa”, “Tere” — dan aplikasi tidak tahu field mana yang memuatnya secara persis. Kebutuhan seperti ini dijawab regular expression: pencocokan pola teks yang fleksibel, bukan kesamaan nilai. MongoDB menerima dua bentuk penulisan regex di dalam filter, menopangnya dengan opsi i, m, s, dan x, serta punya sejumlah aturan performa yang wajib dipahami sebelum dipakai di data besar. Chapter ini menguji semuanya pada katalog nyata.
Peta materi Chapter ini:
- Dua bentuk penulisan: literal
/pola/dan{ $regex: "pola" }. - Empat opsi
$options:i,m,s,x. - Anchor, escaping, dan jebakan penulisan string regex.
- Dampak regex terhadap penggunaan index.
Data Uji: Judul, Penulis, Sinopsis #
Field sinopsis sengaja memuat teks multi-baris untuk menguji opsi m dan s:
use latihan_query
db.buku.drop()Output yang Dihasilkan:
switched to db latihan_query
truedb.buku.insertMany([
{ judul: "Laut Bercerita", penulis: "Leila S. Chudori", harga: 98000, sinopsis: "Berselimut rindu, para eksil menunggu kabar dari tanah air.\nKisah mereka berpindah dari pulau ke pulau." },
{ judul: "Bumi", penulis: "Tere Liye", harga: 89000, sinopsis: "Raib menyusuri koridor akademi.\nIa menemukan pintu menuju dunia lain\nTanpa peta yang jelas." },
{ judul: "Filosofi Teras", penulis: "Henry Manampiring", harga: 89000, sinopsis: "Stoikisme modern untuk pikiran yang lebih tenang." },
{ judul: "Atomic Habits", penulis: "James Clear", harga: 115000, sinopsis: "Perubahan kecil yang memberi hasil luar biasa." },
{ judul: "Rumah Kaca", penulis: "Tere Liye", harga: 72000, sinopsis: "Sekuel dari Bumi, melanjutkan petualangan Raib." }
])Output yang Dihasilkan:
{
acknowledged: true,
insertedIds: {
'0': ObjectId('6ad3918d7985e34b14dacf3b'),
'1': ObjectId('6ad3918d7985e34b14dacf3c'),
'2': ObjectId('6ad3918d7985e34b14dacf3d'),
'3': ObjectId('6ad3918d7985e34b14dacf3e'),
'4': ObjectId('6ad3918d7985e34b14dacf3f')
}
}Dua Bentuk Penulisan #
Bentuk pertama adalah literal regex JavaScript, ditulis langsung sebagai nilai filter. Semua buku Tere Liye:
db.buku.find({ penulis: /Tere/ }, { _id: 0, judul: 1, penulis: 1 })Output yang Dihasilkan:
[
{ judul: 'Bumi', penulis: 'Tere Liye' },
{ judul: 'Rumah Kaca', penulis: 'Tere Liye' }
]Bentuk kedua memakai operator $regex dengan pola sebagai string:
db.buku.find({ judul: { $regex: "Habits" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[ { judul: 'Atomic Habits' } ]Keduanya menghasilkan pencocokan yang sama. Bedanya kegunaan: literal /Tere/ praktis untuk pola yang ditulis langsung di kode, sedangkan bentuk $regex dipakai saat pola dibangun secara dinamis — dari variabel, input pengguna yang sudah divalidasi, atau konfigurasi. Nilai regex literal dikirim sebagai tipe BSON regex; bentuk $regex mengirim string yang ditafsirkan server sebagai pola PCRE.
Opsi: i, m, s, x #
Empat opsi bisa dilewatkan lewat $options (atau flag pada literal, untuk i dan m yang juga dikenal JavaScript):
| Opsi | Nama | Efek |
|---|---|---|
i | case-insensitive | abaikan besar/kecil huruf |
m | multiline | ^ dan $ mencocokkan awal/akhir tiap baris |
s | dotall | . juga mencocokkan karakter baris baru |
x | extended | abaikan spasi tak ter-escape di dalam pola |
Opsi i adalah yang paling sering dipakai — pencarian pengguna tidak peduli kapitalisasi:
db.buku.find({ judul: { $regex: "bumi", $options: "i" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[ { judul: 'Bumi' } ]Kata "bumi" huruf kecil menemukan judul "Bumi". Opsi m dan s berperan pada teks multi-baris. Tanpa m, ^ hanya mencocokkan awal seluruh string; dengan m, awal setiap baris ikut dicocokkan:
db.buku.find({ sinopsis: /^Tanpa/ }, { _id: 0, judul: 1 }).toArray()
db.buku.find({ sinopsis: { $regex: "^Tanpa", $options: "m" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[]
[ { judul: 'Bumi' } ]Kata “Tanpa” berada di awal baris ketiga sinopsis Bumi, bukan awal string, sehingga hanya versi m yang menemukannya. Opsi s membuat . menembus batas baris:
db.buku.find({ sinopsis: { $regex: "lain.Tanpa" } }, { _id: 0, judul: 1 }).toArray()
db.buku.find({ sinopsis: { $regex: "lain.Tanpa", $options: "s" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[]
[ { judul: 'Bumi' } ]Di antara kata lain dan Tanpa tepat berdiri satu karakter baris baru. Tanpa s, . menolak karakter itu; dengan s, pola lain.Tanpa cocok. Opsi x mengabaikan spasi di dalam pola — berguna untuk merapikan pola panjang:
db.buku.find({ judul: { $regex: "^ B u m i", $options: "x" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[ { judul: 'Bumi' } ]Anchor, Escaping, dan Jebakan String #
Anchor membatasi posisi kecocokan: ^ awal, $ akhir. Kombinasi keduanya menjadikan regex padanan kesamaan persis — cocok untuk validasi format:
db.buku.find({ judul: { $regex: "^Rumah Kaca$" } }, { _id: 0, judul: 1 })Output yang Dihasilkan:
[ { judul: 'Rumah Kaca' } ]Karakter khusus regex dicocokkan literal dengan backslash. Penulis Leila S. Chudori memuat titik; pola /S\./ mencocokkan huruf S diikuti titik sungguhan:
db.buku.find({ penulis: /S\./ }, { _id: 0, judul: 1, penulis: 1 })Output yang Dihasilkan:
[ { judul: 'Laut Bercerita', penulis: 'Leila S. Chudori' } ]Satu jebakan penulisan khas bentuk $regex: pola string tidak boleh dibungkus garis miring seperti di JavaScript. String "/Bumi/" berarti pola yang memuat karakter / literal:
db.buku.find({ judul: { $regex: "/Bumi/" } }, { _id: 0, judul: 1 }).toArray()Output yang Dihasilkan:
[]Hasil kosong — tidak ada judul yang memuat karakter /. Tulis { $regex: "Bumi" } tanpa garis miring; flag seperti i cukup dipindahkan ke $options.
Regex dan Index #
Regex bisa memakai index hanya dalam satu kondisi: pola berawalan tetap (prefix) dan case-sensitive, seperti /^Bumi/. Dengan index atas field tersebut, server membuka index langsung pada rentang kunci yang berawalan Bumi — nyaris secepat query kesamaan. Sebaliknya, pola tanpa awalan (/Bumi/ mencari di mana pun dalam string) atau yang case-insensitive (/^bumi/i harus membandingkan setiap variasi kapital) memaksa server memeriksa setiap kunci satu per satu.
Kita membuktikan klaim performa ini dengan explain() dan melihat jenis pemindaian yang dipilih server di Chapter Dasar Performa Query — chapter penutup section ini.
Rangkuman #
- Dua bentuk penulisan: literal
/pola/(statis) dan{ $regex: "pola" }(dinamis); jangan bungkus pola string dengan garis miring. $optionsmengaktifkani(abaikan kapital),m(anchor per baris),s(.menembus baris baru),x(abaikan spasi pola).^...$membatasi posisi kecocokan; karakter khusus di-escape dengan backslash.- Hanya prefix regex case-sensitive yang bisa memakai index secara rapat; sisanya memindai seluruh kunci — pertimbangkan
$textindex untuk pencarian teks.