I have data like this:
{
"_id": "n383hopmfz69j7rdbh1ny56g",
"playerId": "402ddb96-0edf-4df7-9ba8-ffb201ef6a70",
"playedChartId": "3w2aaz0ryd58it6r3w0klu5r",
"score": 966858
},
{
"_id": "5e83ecd30102b60ea4a11fe9",
"playerId": "402ddb96-0edf-4df7-9ba8-ffb201ef6a70", // the same player
"playedChartId": "3w2aaz0ryd58it6r3w0klu5r",
"score": 954201 // with lower score
},
{
"_id": "629da76873dff6547eb1e9b3",
"playerId": "f6fe9c4d-98e6-450a-937c-d64848eacc40", // the different player
"playedChartId": "3w2aaz0ryd58it6r3w0klu5r", // the same chart
"score": 902238
}
As I know how to filter 'playedChartId', so I ignored the other documents with different 'playedChartId'.
Then I want to group them by 'playerId', find the document with the best 'score', with 'ranking'.
The result I wanted:
[
{
// the original document
"_id": "n383hopmfz69j7rdbh1ny56g",
"playerId": "402ddb96-0edf-4df7-9ba8-ffb201ef6a70",
"playedChartId": "3w2aaz0ryd58it6r3w0klu5r",
"score": 966858,
// the generated ranking value
"ranking": 1
},
{
"_id": "n383hopmfz69j7rdbh1ny56g",
"playerId": "f6fe9c4d-98e6-450a-937c-d64848eacc40", // the different player
"playedChartId": "3w2aaz0ryd58it6r3w0klu5r", // the same chart
"score": 902238,
"ranking": 2
}
]
CodePudding user response:
$sort
- Order byplayerId
then byscore
descending.$group
- Group byplayerId
, and take the first document asdata
via$first
.$replaceWith
- Replace input document withdata
.$setWindowFields
- Perform ranking via$rank
order byscore
descending.
db.collection.aggregate([
{
$sort: {
playerId: 1,
score: -1
}
},
{
$group: {
_id: "$playerId",
data: {
$first: "$$ROOT"
}
}
},
{
$replaceWith: "$data"
},
{
$setWindowFields: {
sortBy: {
score: -1
},
output: {
ranking: {
$rank: {}
}
}
}
}
])