Je sais que cette question est ancienne, mais je l'ai trouvée sur Google après avoir répondu à une nouvelle question similaire . J'ai donc pensé que cela méritait le même traitement.
Vous pouvez éviter l'impact sur les performances de $where en utilisant aggregate à la place :
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 }}
])
Et cela devrait tourner autour de $where puisque nous avons pu affiner les documents qui avaient un commentaire de "Abe" en premier lieu. Comme averti, $where va tester chaque document de la collection et ne jamais utiliser d'index même s'il y en a un pour être utilisé.
Bien sûr, vous pouvez également conserver le document original en utilisant la technique décrite ici
ainsi, tout fonctionnerait comme un find()
.
Juste matière à réflexion pour quiconque trouve cela.
Mise à jour pour les versions modernes de MongoDB
Les versions modernes ont ajouté le $redact
expression de pipeline ainsi que $arrayElemAt
(ce dernier à partir de 3.2, donc ce serait la version minimale ici) qui, en combinaison, permettrait à une expression logique d'inspecter le dernier élément d'un tableau sans traiter un $unwind
étape :
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
La logique ici est faite en comparaison où $arrayElemAt
obtient le dernier index du tableau -1
, qui est transformé en un simple tableau des valeurs dans le "by"
propriété via $map
. Cela permet de comparer la valeur unique avec le paramètre requis, "Abe"
.
Ou même un peu plus moderne en utilisant $expr
pour MongoDB 3.6 et supérieur :
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Ce serait de loin la solution la plus performante pour faire correspondre le dernier élément d'un tableau, et devrait en fait remplacer l'utilisation de $where
dans la plupart des cas et surtout ici.