Jeg ved, at dette spørgsmål er gammelt, men jeg fandt det på google efter at have besvaret et lignende nyt spørgsmål . Så jeg syntes, at det her fortjente den samme behandling.
Du kan undgå ydeevnehittet af $where ved at bruge aggregat i stedet:
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 }}
])
Og det burde løbe ringe rundt $where da vi var i stand til at indsnævre de dokumenter, der havde en kommentar af "Abe" i første omgang. Som advaret, $where vil teste hvert dokument i samlingen og aldrig bruge et indeks, selvom et er der for at blive brugt.
Du kan selvfølgelig også vedligeholde det originale dokument ved hjælp af teknikken beskrevet her
også, så alt ville fungere ligesom en find()
.
Bare stof til eftertanke for alle, der finder dette.
Opdatering til moderne MongoDB-udgivelser
Moderne udgivelser har tilføjet $redact
pipeline-udtryk samt $arrayElemAt
( sidstnævnte fra 3.2, så det ville være den minimale version her ), som i kombination ville tillade et logisk udtryk at inspicere det sidste element i en matrix uden at behandle en $unwind
fase:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Logikken her er lavet i sammenligning hvor $arrayElemAt
får det sidste indeks for arrayet -1
, som er transformeret til kun en matrix af værdierne i "by"
ejendom via $map
. Dette tillader sammenligning af den enkelte værdi med den påkrævede parameter, "Abe"
.
Eller endda lidt mere moderne ved at bruge $expr
til MongoDB 3.6 og nyere:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Dette ville være langt den mest effektive løsning til at matche det sidste element i et array og forventes faktisk at erstatte brugen af $where
i de fleste tilfælde og især her.