Sei que esta pergunta é antiga, mas a encontrei no google depois de responder a uma nova pergunta semelhante . Então eu pensei que isso merecia o mesmo tratamento.
Você pode evitar o impacto no desempenho de $where usando agregado em vez de:
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 }}
])
E isso deve rodar em torno de $where já que conseguimos restringir os documentos que tinham um comentário de "Abe" em primeiro lugar. Conforme avisado, $where vai testar todos os documentos da coleção e nunca usar um índice, mesmo que exista um para ser usado.
Claro, você também pode manter o documento original usando a técnica descrita aqui também, então tudo funcionaria como um
find()
. Apenas alimento para o pensamento para quem encontrar isso.
Atualização para versões modernas do MongoDB
As versões modernas adicionaram o
$redact
expressão de pipeline, bem como $arrayElemAt
(o último a partir de 3.2, então essa seria a versão mínima aqui) que, em combinação, permitiria que uma expressão lógica inspecionasse o último elemento de um array sem processar um $unwind
palco:db.example.aggregate([
{ "$match": { "comments.by": "Abe" }},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
A lógica aqui é feita em comparação onde
$arrayElemAt
está obtendo o último índice do array -1
, que é transformado em apenas uma matriz dos valores no "by"
propriedade via $map
. Isso permite a comparação do valor único com o parâmetro necessário, "Abe"
. Ou até um pouco mais moderno usando
$expr
para MongoDB 3.6 e superior:db.example.find({
"comments.by": "Abe",
"$expr": {
"$eq": [
{ "$arrayElemAt": [ "$comments.by", -1 ] },
"Abe"
]
}
})
Esta seria de longe a solução de melhor desempenho para combinar o último elemento dentro de uma matriz e, na verdade, deve substituir o uso de
$where
na maioria dos casos e especialmente aqui.