A melhor maneira de fazer isso é usando a estrutura de agregação. Você precisa
$group
seus documentos por "usuário" e retorne o último documento para cada usuário usando o $last
operador acumulador, mas para que isso funcione, você precisa de um estágio de classificação preliminar usando o $sort
operador de pipeline de agregação. Para classificar seus documentos, você precisa considerar tanto o campo "createdAt" quanto o campo "user". O último estágio no pipeline é o
$match
estágio em que você seleciona apenas os últimos documentos em que "isAbandonado" é igual a true
. db.students.aggregate([
{ "$sort": { "user": 1, "createdAt": 1 } },
{ "$group": {
"_id": "$user",
"last": { "$last": "$$ROOT" }
}},
{ "$match": { "last.isAbandoned": true } }
])
que retorna algo assim:
{
"_id" : ObjectId("56c85244bd5f92cd78ae4bc1"),
"last" : {
"_id" : ObjectId("56cee51503b7cb7b0eda9c4c"),
"user" : ObjectId("56c85244bd5f92cd78ae4bc1"),
"studentName" : "Rajeev",
"createdAt" : ISODate("2016-02-25T11:27:17.281Z"),
"isAbandoned" : true
}
}
Para obter o resultado esperado, precisamos usar o
$replaceRoot
operador de pipeline a partir da versão 3.4 para promover o documento incorporado ao nível superior {
$replaceRoot: { newRoot: "$last" }
}
Na versão mais antiga, você precisa usar o
$project
operação de pipeline de agregação para reformular nossos documentos. Então, se estendermos nosso pipeline com o seguinte estágio:{
"$project": {
"_id": "$last._id",
"user": "$last.user",
"studentName": "$last.studentName",
"createdAt": "$last.createdAt",
"isAbandoned": "$last.isAbandoned"
}}
ele produz a saída esperada:
{
"_id" : ObjectId("56cee51503b7cb7b0eda9c4c"),
"user" : ObjectId("56c85244bd5f92cd78ae4bc1"),
"studentName" : "Rajeev",
"createdAt" : ISODate("2016-02-25T11:27:17.281Z"),
"isAbandoned" : true
}