Jag vet att den här frågan är gammal, men jag hittade den på google efter att ha svarat på en liknande ny fråga . Så jag tyckte att det här förtjänade samma behandling.
Du kan undvika prestandaträffen för $where genom att använda aggregat istället:
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 }}
])
Och det borde ringa runt $where eftersom vi kunde begränsa de dokument som hade en kommentar av "Abe" i första hand. Som varnat, $where kommer att testa alla dokument i samlingen och aldrig använda ett index även om ett finns där för att användas.
Naturligtvis kan du också underhålla originaldokumentet med tekniken som beskrivs här
likaså, så allt skulle fungera precis som en find()
.
Bara en tankeställare för alla som hittar detta.
Uppdatering för moderna MongoDB-versioner
Moderna utgåvor har lagt till $redact
pipeline-uttryck samt $arrayElemAt
(den senare från och med 3.2, så det skulle vara den minimala versionen här ) som i kombination skulle tillåta ett logiskt uttryck att inspektera det sista elementet i en array utan att bearbeta en $unwind
steg:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Logiken här görs i jämförelse där $arrayElemAt
får det sista indexet för arrayen -1
, som omvandlas till bara en array av värdena i "by"
egendom via $map
. Detta möjliggör jämförelse av det enstaka värdet mot den önskade parametern, "Abe"
.
Eller till och med lite modernare med $expr
för MongoDB 3.6 och senare:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Detta skulle vara den överlägset mest presterande lösningen för att matcha det sista elementet i en array, och förväntas faktiskt ersätta användningen av $where
i de flesta fall och särskilt här.