Знам, че този въпрос е стар, но го намерих в Google, след като отговорих на подобен нов въпрос . Така че реших, че това заслужава същото отношение.
Можете да избегнете удара в производителността на $where чрез използване на aggregate вместо това:
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 }}
])
И това трябва да обикаля около $where тъй като успяхме да стесним обхвата на документите, които има коментар на "Абе" на първо място. Както беше предупредено, $where ще тества всеки документ в колекцията и никога няма да използва индекс, дори ако има такъв за използване.
Разбира се, можете също да поддържате оригиналния документ, като използвате техниката, описана тук
също така, така че всичко ще работи точно като find()
.
Само храна за размисъл за всеки, който открие това.
Актуализация за модерни версии на MongoDB
Съвременните версии са добавили $redact
тръбопроводен израз, както и $arrayElemAt
(последното от 3.2, така че това ще бъде минималната версия тук), което в комбинация ще позволи на логически израз да инспектира последния елемент от масив, без да обработва $unwind
етап:
db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Логиката тук се прави в сравнение, когато $arrayElemAt
получава последния индекс на масива -1
, който се трансформира само в масив от стойностите в "by"
собственост чрез $map
. Това позволява сравнение на единичната стойност с необходимия параметър, "Abe"
.
Или дори малко по-модерно, използвайки $expr
за MongoDB 3.6 и по-нови:
db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Това би било най-ефективното решение за съпоставяне на последния елемент в масив и всъщност се очаква да замести използването на $where
в повечето случаи и особено тук.