Saya tahu pertanyaan ini sudah lama, tetapi saya menemukannya di google setelah menjawab pertanyaan baru yang serupa . Jadi saya pikir ini pantas mendapatkan perlakuan yang sama.
Anda dapat menghindari hit kinerja $where dengan menggunakan agregat sebagai gantinya:
db.example.aggregate([
// Use an index, which $where cannot to narrow down
{$match: { "comments.by": "Abe" }},
// De-normalize the Array
{$unwind: "$comments"},
// The order of the array is maintained, so just look for the $last by _id
{$group: { _id: "$_id", comments: {$last: "$comment"} }},
// Match only where that $last comment by `by.Abe`
{$match: { "comments.by": "Abe" }},
// Retain the original _id order
{$sort: { _id: 1 }}
])
Dan itu akan berdering di sekitar $where karena kami dapat mempersempit dokumen yang memiliki komentar oleh "Abe" di tempat pertama. Seperti yang diperingatkan, $where akan menguji setiap dokumen dalam koleksi dan tidak pernah menggunakan indeks meskipun ada yang akan digunakan.
Tentu saja, Anda juga dapat memelihara dokumen asli menggunakan teknik yang dijelaskan di sini
juga, jadi semuanya akan berfungsi seperti find()
.
Hanya bahan pemikiran bagi siapa pun yang menemukan ini.
Pembaruan untuk rilis MongoDB Modern
Rilis modern telah menambahkan $redact
ekspresi pipeline serta $arrayElemAt
( yang terakhir pada 3.2, sehingga akan menjadi versi minimal di sini ) yang dalam kombinasi akan memungkinkan ekspresi logis untuk memeriksa elemen terakhir dari sebuah array tanpa memproses $unwind
panggung:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Logika di sini dilakukan dengan membandingkan $arrayElemAt
mendapatkan indeks terakhir dari array -1
, yang ditransformasikan menjadi hanya larik nilai dalam "by"
properti melalui $map
. Ini memungkinkan perbandingan nilai tunggal terhadap parameter yang diperlukan, "Abe"
.
Atau bahkan sedikit lebih modern menggunakan $expr
untuk MongoDB 3.6 dan yang lebih baru:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Ini akan menjadi solusi paling berkinerja untuk mencocokkan elemen terakhir dalam array, dan sebenarnya diharapkan untuk menggantikan penggunaan $where
dalam banyak kasus dan khususnya di sini.