I've got a mongoDB collection that looks like:
[
{user: "joe", event: "foo", timestamp: 1},
{user: "meg", event: "blah", timestamp: 2},
{user: "rick", event: "bork", timestamp: 3},
{user: "joe", event: "bing", timestamp: 4},
{user: "meg", event: "biz", timestamp: 5},
{user: "tim", event: "boz", timestamp: 6}
]
and I want to find the latest event for each user, so get a set of results like:
[
{user: "rick", event: "bork", timestamp: 3},
{user: "joe", event: "bing", timestamp: 4},
{user: "meg", event: "biz", timestamp: 5},
{user: "tim", event: "boz", timestamp: 6}
]
I've looked over the mongoose aggregation framework docs, and it seems like there should be a way to do this simply, but none of the examples I've seen do quite exactly this. Lots of them group by user, but then the resulting groupings lose some of the data, and I'm not sure how to reconstitute the full documents at the end.
$setWindowFields
- Partition/Group the document by the user
field, order each partition by timestamp
descending, and add the rank
field with the $rank
operator.
$match
- Filter the document with rank: 1
indicates getting the document with the latest timestamp for each partition.
$sort
- Order the document by timestamp
ascending.
$unset
- Remove the rank
field from the documents.
db.collection.aggregate([
{
$setWindowFields: {
partitionBy: "$user",
sortBy: {
timestamp: -1
},
output: {
rank: {
$rank: {}
}
}
}
},
{
$match: {
rank: 1
}
},
{
$sort: {
timestamp: 1
}
},
{
$unset: "rank"
}
])