Jarak tempuh dapat bervariasi dalam hal ini dan mungkin ternyata "saat ini" proses yang Anda ikuti setidaknya "paling cocok". Tapi kita mungkin bisa melakukannya dengan lebih efisien.
Apa yang dapat Anda lakukan sekarang
Asalkan array Anda sudah "diurutkan" melalui menggunakan $sort
pengubah dengan $push
, maka Anda mungkin dapat melakukan ini:
db.somedb.find(
{
"partn.is_partner": true,
"$where": function() {
return this.partn.slice(-1)[0].is_partner == true;
}
},
{ "partn": { "$slice": -1 } }
)
Jadi selama partn,is_partner
adalah "diindeks" ini masih cukup efisien karena kondisi kueri awal itu dapat dipenuhi menggunakan indeks. Bagian yang tidak bisa adalah $where
klausa di sini yang menggunakan evaluasi JavaScript.
Tapi apa bagian kedua di $where
lakukan hanyalah "mengiris" elemen terakhir dari array dan menguji nilainya dari is_partner
properti untuk melihat apakah itu benar. Hanya jika kondisi itu juga terpenuhi, dokumen dikembalikan.
Ada juga $slice
operator proyeksi. Ini melakukan hal yang sama dalam mengembalikan elemen terakhir dari array. Pencocokan palsu sudah difilter, jadi ini hanya menampilkan elemen terakhir yang benar.
Dikombinasikan dengan indeks seperti yang disebutkan, maka ini akan cukup cepat mengingat dokumen telah dipilih dan kondisi JavaScript hanya memfilter sisanya. Perhatikan bahwa tanpa bidang lain dengan kondisi kueri standar yang cocok, sebuah $where
klausa tidak dapat menggunakan indeks. Jadi, selalu coba gunakan "hemat" dengan kondisi kueri lainnya.
Apa yang dapat Anda lakukan di masa depan
Selanjutnya, meskipun tidak tersedia pada saat penulisan, tetapi pasti dalam waktu dekat akan menjadi $slice
operator untuk kerangka agregasi. Ini saat ini di cabang pengembangan, tetapi di sini adalah cara kerjanya:
db.somedb.aggregate([
{ "$match": { "partn.is_partner": true } },
{ "$redact": {
"$cond": {
"if": {
"$anyElementTrue": {
"$map": {
"input": { "$slice": ["$partn",-1] },
"as": "el",
"in": "$$el.is_partner"
}
}
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}},
{ "$project": {
"partn": { "$slice": [ "$partn",-1 ] }
}}
])
Menggabungkan $slice
dalam $redact
tahap disini memungkinkan dokumen difilter dengan kondisi logis, pengujian dokumen. Dalam hal ini $slice
menghasilkan larik elemen tunggal yang dikirim ke $map
untuk hanya mengekstrak is_partner
tunggal nilai ( masih sebagai array ). Karena ini masih merupakan larik elemen tunggal, tes lainnya adalah $anyElementTrue
$cond
.
$redact
di sini memutuskan hasil tersebut apakah akan $$KEEP
atau $$PRUNE
dokumen dari hasil. Nanti kita gunakan $slice
lagi dalam proyek untuk hanya mengembalikan elemen terakhir dari array setelah pemfilteran.
Itu bekerja persis seperti yang dilakukan versi JavaScript, dengan pengecualian bahwa ini menggunakan semua operator berkode asli, dan karenanya harus sedikit lebih cepat daripada alternatif JavaScript.
Kedua formulir mengembalikan dokumen pertama Anda seperti yang diharapkan:
{
"_id" : 0,
"partn" : [
{
"date" : ISODate("2015-07-28T00:59:14.963Z"),
"is_partner" : true
},
{
"date" : ISODate("2015-07-28T01:00:32.771Z"),
"is_partner" : false
},
{
"date" : ISODate("2015-07-28T01:15:29.916Z"),
"is_partner" : true
},
{
"date" : ISODate("2015-08-05T13:48:07.035Z"),
"is_partner" : false
},
{
"date" : ISODate("2015-08-05T13:50:56.482Z"),
"is_partner" : true
}
]
}
Tangkapan besar di sini dengan keduanya adalah array Anda harus sudah diurutkan sehingga tanggal terbaru adalah yang pertama. Tanpa itu, maka Anda memerlukan kerangka kerja agregasi untuk $sort
array, seperti yang Anda lakukan sekarang.
Tidak terlalu efisien, jadi itu sebabnya Anda harus "menyortir" array Anda dan mempertahankan urutannya pada setiap pembaruan.
Sebagai trik praktis, ini sebenarnya akan mengurutkan ulang semua elemen array di semua dokumen koleksi dalam satu pernyataan sederhana:
db.somedb.update(
{},
{ "$push": {
"partn": { "$each": [], "$sort": { "date": 1 } }
}},
{ "multi": true }
)
Jadi, bahkan jika Anda tidak "mendorong" elemen baru ke dalam array dan hanya memperbarui properti, Anda selalu dapat menerapkan konstruksi dasar itu untuk menjaga agar array tetap teratur seperti yang Anda inginkan.
Layak dipertimbangkan karena seharusnya membuat segalanya lebih cepat.