Field berupa array sangat umum ditemui pada dokumen MongoDB, misalnya daftar label pada buku atau daftar salinan pada koleksi perpustakaan. Topik ini membahas cara mengquery field array, mulai pencocokan satu elemen, pencocokan array utuh, operator $all dan $size, sampai $elemMatch untuk beberapa syarat pada elemen yang sama. Data contohnya berupa enam buku yang masing-masing memuat array tags berisi label dan array salinan berisi subdokumen letak rak.
Pencocokan satu elemen dan array utuh#
Menuliskan satu nilai pada field array berarti meminta kecocokan pada salah satu elemennya. MongoDB mengembalikan dokumen apabila sekurang-kurangnya satu elemen array sama dengan nilai tersebut, tanpa memperhatikan posisi elemennya. Apabila nilai filternya berupa array utuh, pencocokannya berubah menjadi eksak, yaitu urutan dan jumlah elemennya harus sama persis.
Siapkan data contoh berikut.
use perpustakaanswitched to db perpustakaandb.buku.insertMany([
{ judul: "Masakan Nusantara", pengarang: "Dewi Kartika", tags: ["masakan", "budaya"], salinan: [ { rak: "A", tersedia: true }, { rak: "B", tersedia: false } ] },
{ judul: "Panduan Fotografi", pengarang: "Budi Santoso", tags: ["hobi", "teknik"], salinan: [ { rak: "A", tersedia: false } ] },
{ judul: "Sejarah Asia Tenggara", pengarang: "Citra Melati", tags: ["sejarah", "budaya"], salinan: [ { rak: "C", tersedia: true }, { rak: "A", tersedia: false } ] },
{ judul: "Mengelola Keuangan Pribadi", pengarang: "Rina Wulandari", tags: ["keuangan"], salinan: [ { rak: "B", tersedia: true } ] },
{ judul: "Peta Langit untuk Pemula", pengarang: "Ali Rahman", tags: ["astronomi", "hobi"], salinan: [ { rak: "A", tersedia: true }, { rak: "C", tersedia: true } ] },
{ judul: "Taman Bunga Tropis", pengarang: "Dewi Kartika", tags: ["berkebun", "hobi"], salinan: [ { rak: "B", tersedia: true }, { rak: "C", tersedia: true }, { rak: "A", tersedia: true } ] }
]){
acknowledged: true,
insertedIds: {
'0': ObjectId('6ae85f4038bf4ce9c5ce5f47'),
'1': ObjectId('6ae85f4038bf4ce9c5ce5f48'),
'2': ObjectId('6ae85f4038bf4ce9c5ce5f49'),
'3': ObjectId('6ae85f4038bf4ce9c5ce5f4a'),
'4': ObjectId('6ae85f4038bf4ce9c5ce5f4b'),
'5': ObjectId('6ae85f4038bf4ce9c5ce5f4c')
}
}Saring koleksi dengan satu nilai label, lalu bandingkan dengan pencocokan array utuh.
db.buku.find({ tags: "budaya" })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f47'),
judul: 'Masakan Nusantara',
pengarang: 'Dewi Kartika',
tags: [ 'masakan', 'budaya' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'B', tersedia: false } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f49'),
judul: 'Sejarah Asia Tenggara',
pengarang: 'Citra Melati',
tags: [ 'sejarah', 'budaya' ],
salinan: [ { rak: 'C', tersedia: true }, { rak: 'A', tersedia: false } ]
}
]db.buku.find({ tags: ["budaya", "masakan"] })
db.buku.find({ tags: ["masakan", "budaya"] })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f47'),
judul: 'Masakan Nusantara',
pengarang: 'Dewi Kartika',
tags: [ 'masakan', 'budaya' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'B', tersedia: false } ]
}
]Query dengan satu nilai label mengembalikan dua buku yang memuat label budaya pada posisi mana pun. Pada dua query array utuh di atas, urutan terbalik tidak menghasilkan apa pun, sedangkan urutan yang persis sama dengan datanya mengembalikan satu buku. Perbedaan ini menunjukkan bahwa array sebagai nilai filter bersifat ketat terhadap urutan.
Operator $all#
Operator $all menuntut seluruh nilai dalam daftarnya hadir pada array, tanpa memperhatikan urutan dan tanpa melarang elemen tambahan. Bentuk penulisannya sama seperti $in, yaitu daftar nilai di dalam array pada sisi operator. Operator ini cocok untuk pencarian yang menuntut beberapa label sekaligus.
db.buku.find({ tags: { $all: ["hobi", "astronomi"] } })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4b'),
judul: 'Peta Langit untuk Pemula',
pengarang: 'Ali Rahman',
tags: [ 'astronomi', 'hobi' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'C', tersedia: true } ]
}
]Hasilnya satu buku yang array tags-nya memuat kedua label tersebut. Pencocokan array utuh ["astronomi", "hobi"] juga akan mengembalikan dokumen yang sama, tetapi $all tetap bekerja apabila arraynya menyimpan elemen lain. Dengan satu label saja, $all berperilaku sama seperti pencocokan satu elemen biasa.
Operator $size#
Operator $size mencocokkan array berdasarkan jumlah elemennya, bukan berdasarkan isinya. Nilainya harus berupa bilangan bulat yang persis, sehingga tidak ada bentuk rentang seperti minimal dua elemen. Operator ini sering digabungkan dengan syarat lain agar array pendek maupun panjang dapat dipilah.
db.buku.find({ tags: { $size: 1 } })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4a'),
judul: 'Mengelola Keuangan Pribadi',
pengarang: 'Rina Wulandari',
tags: [ 'keuangan' ],
salinan: [ { rak: 'B', tersedia: true } ]
}
]Hasilnya satu buku dengan satu label saja. Apabila kebutuhannya adalah array dengan sekurang-kurangnya dua elemen, $size tidak dapat menyatakan hal tersebut, dan penanganannya memerlukan trik query tambahan. Karena itu, $size paling tepat digunakan ketika jumlah elemen memang bernilai pasti pada desain data.
Operator $elemMatch#
Operator $elemMatch menuntut satu elemen array memenuhi beberapa syarat sekaligus. Syarat-syaratnya ditulis dalam satu objek pada sisi operator, dan seluruhnya harus terpenuhi oleh elemen yang sama. Tanpa $elemMatch, syarat pada field bersarang dapat terpenuhi oleh elemen yang berbeda-beda, seperti yang akan dibandingkan berikut ini.
db.buku.find({ salinan: { $elemMatch: { rak: "A", tersedia: true } } })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f47'),
judul: 'Masakan Nusantara',
pengarang: 'Dewi Kartika',
tags: [ 'masakan', 'budaya' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'B', tersedia: false } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4b'),
judul: 'Peta Langit untuk Pemula',
pengarang: 'Ali Rahman',
tags: [ 'astronomi', 'hobi' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'C', tersedia: true } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4c'),
judul: 'Taman Bunga Tropis',
pengarang: 'Dewi Kartika',
tags: [ 'berkebun', 'hobi' ],
salinan: [
{ rak: 'B', tersedia: true },
{ rak: 'C', tersedia: true },
{ rak: 'A', tersedia: true }
]
}
]Hasilnya tiga buku yang masing-masing memiliki satu salinan di rak A dan tersedia pada saat yang sama. Buku dengan salinan rak A yang tidak tersedia tidak ikut muncul, sebab kedua syarat wajib berada pada satu subdokumen. Bandingkan dengan query bertanda titik berikut.
db.buku.find({ "salinan.rak": "A", "salinan.tersedia": true })[
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f47'),
judul: 'Masakan Nusantara',
pengarang: 'Dewi Kartika',
tags: [ 'masakan', 'budaya' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'B', tersedia: false } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f49'),
judul: 'Sejarah Asia Tenggara',
pengarang: 'Citra Melati',
tags: [ 'sejarah', 'budaya' ],
salinan: [ { rak: 'C', tersedia: true }, { rak: 'A', tersedia: false } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4b'),
judul: 'Peta Langit untuk Pemula',
pengarang: 'Ali Rahman',
tags: [ 'astronomi', 'hobi' ],
salinan: [ { rak: 'A', tersedia: true }, { rak: 'C', tersedia: true } ]
},
{
_id: ObjectId('6ae85f4038bf4ce9c5ce5f4c'),
judul: 'Taman Bunga Tropis',
pengarang: 'Dewi Kartika',
tags: [ 'berkebun', 'hobi' ],
salinan: [
{ rak: 'B', tersedia: true },
{ rak: 'C', tersedia: true },
{ rak: 'A', tersedia: true }
]
}
]Hasilnya empat buku, satu lebih banyak dari query $elemMatch. Buku tambahan tersebut masuk karena syarat rak A terpenuhi oleh satu salinan, sedangkan syarat tersedia terpenuhi oleh salinan lain yang berbeda rak. Perilaku ini bukan kesalahan server, melainkan makna bawaan notasi titik pada field array.
Ringkasan#
- Satu nilai pada field array mencocokkan salah satu elemennya, sedangkan array sebagai nilai filter menuntut kecocokan utuh termasuk urutannya.
$allmenuntut seluruh nilai daftarnya hadir tanpa memperhatikan urutan, dan$sizemencocokkan jumlah elemen secara persis.$elemMatchmenuntut satu elemen memenuhi seluruh syarat sekaligus, sehingga aman untuk field bersarang dengan beberapa syarat.- Notasi titik pada field array dapat mencocokkan syarat pada elemen yang berbeda, sehingga maknanya berbeda dari
$elemMatch.
Referensi#
- Query Arrays — MongoDB Manual — Tutorial resmi pencarian pada field array beserta contohnya.
- $all — MongoDB Manual — Dokumentasi operator $all untuk pencocokan seluruh elemen.
- $size — MongoDB Manual — Dokumentasi operator $size untuk jumlah elemen array.
- $elemMatch — MongoDB Manual — Dokumentasi operator $elemMatch untuk beberapa syarat pada satu elemen.