Ik weet dat deze vraag oud is, maar ik vond hem op Google na het beantwoorden van een vergelijkbare nieuwe vraag . Dus ik dacht dat dit dezelfde behandeling verdiende.
U kunt de prestatiehit van $where vermijden door gebruik te maken van aggregaat in plaats daarvan:
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 }}
])
En dat zou moeten draaien rond $where omdat we de documenten konden beperken die had een opmerking van "Abe" in de eerste plaats. Zoals gewaarschuwd, $where gaat elk document in de collectie testen en nooit een index gebruiken, ook al is er een om te gebruiken.
Natuurlijk kunt u het originele document ook behouden met behulp van de techniek die hier wordt beschreven
ook, dus alles zou werken als een find()
.
Gewoon stof tot nadenken voor iedereen die dit vindt.
Update voor moderne MongoDB-releases
Moderne releases hebben de $redact
toegevoegd
pijplijnexpressie evenals $arrayElemAt
( de laatste vanaf 3.2, dus dat zou hier de minimale versie zijn ) die in combinatie een logische expressie in staat zou stellen om het laatste element van een array te inspecteren zonder een $unwind
stadium:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
De logica hier wordt gedaan in vergelijking waar $arrayElemAt
krijgt de laatste index van de array -1
, die wordt omgezet in slechts een array van de waarden in de "by"
eigendom via $map
. Hierdoor kan de enkele waarde worden vergeleken met de vereiste parameter, "Abe"
.
Of zelfs een beetje moderner met $expr
voor MongoDB 3.6 en hoger:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Dit zou verreweg de meest performante oplossing zijn voor het matchen van het laatste element binnen een array, en zou eigenlijk het gebruik van $where
in de meeste gevallen en vooral hier.