MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Consulta no último valor da matriz


O principal aqui é a agregação $slice para obter o último elemento da matriz,
db.chat.aggregate([
 { "$match": { "user1": 1,  "messages.capty": "B" } },
 { "$redact": {
   "$cond": {
     "if": { 
       "$eq": [ { "$slice": [ "$messages.capty", -1 ] }, ["B"] ]  
     },
     "then": "$$KEEP",
     "else": "$$PRUNE"
   }
 }},
 { "$project": {
   "user2": 1,
   "body": {
     "$arrayElemAt": [
       { "$map": {
         "input": { 
           "$filter": {
             "input": { "$slice": [ "$messages",-1 ] },
             "as": "m",
             "cond": { "$eq": [ "$$m.capty", "B" ] }
           }
         },
         "as": "m",
         "in": "$$m.body"
       }},
       0
     ]
   }
 }}
])

Na verdade, estou sendo "extra seguro" no $project estágio com o $filter mas tudo basicamente o mesmo.

Primeiro, a consulta seleciona os documentos, não podemos dizer neste momento para "apenas" corresponder ao último elemento da matriz, mas queremos filtrar documentos que não têm a condição na matriz.

O $redact é a coisa real que analisa a "última" entrada da matriz e testa o valor do campo. Podemos anotar apenas o campo do array por $messages.capty que retorna apenas uma matriz desses itens. Aqui nós então $slice ou mesmo $arrayElemAt se você deseja obter o último valor, sendo o índice de -1 .

Neste ponto, apenas "filtramos" os "documentos" que não correspondem à condição. O $project final stage pega o último elemento do array, verifica se ele corresponde à condição (o que deveria nos estágios anteriores), extrai o valor de "body" e transforma o conteúdo da matriz única em apenas o valor simples.

Você pode alternadamente renunciar ao "cuidado" e simplesmente pegar o último elemento do array desde $redact deveria ter feito seu trabalho:
db.chat.aggregate([
 { "$match": { "user1": 1,  "messages.capty": "B" } },
 { "$redact": {
   "$cond": {
     "if": { 
       "$eq": [ { "$arrayElemAt": [ "$messages.capty", -1 ] }, "B" ]  
     },
     "then": "$$KEEP",
     "else": "$$PRUNE"
   }
 }},
 { "$project": {
   "user2": 1,
   "body": {
     "$arrayElemAt": [ "$messages.body", -1 ]
   }
 }}
])

A coisa toda realmente se resume a "combinar com o possível documentos com uma consulta" e depois "compare e extraia o último elemento com $slice ou $arrayElemAt ".

Os resultados são:
{
        "_id" : ObjectId("593921425ccc8150f35e7663"),
        "user2" : 3,
        "body" : "hiii 23"
}
{
        "_id" : ObjectId("593921425ccc8150f35e7664"),
        "user2" : 4,
        "body" : "hiii 24"
}