本文是Mongo語法實現的實時用戶排名,支持Mongo3.4、4.2版本
數據樣例
db.grade.insert({'name':'張三', 'grade':100});
db.grade.insert({'name':'李四', 'grade':95});
db.grade.insert({'name':'王五', 'grade':95});
db.grade.insert({'name':'趙六', 'grade':70});
db.grade.insert({'name':'李', 'grade':0});
db.grade.insert({'name':'錢', 'grade':0});
一、方案1:同分不同排名
如:李四、王五 分數一樣,排名 可能是李四-2(王五-3),也可能王五-2
實現方案
按成績降序排列,然後合併成數組(數組有下標,可以當排名用),再將數組拆分成多條記錄,拆分時帶上數組所在下標位置
Mongo語句
db.grade.aggregate([
{
$sort:{
'grade':-1
}
},
// 將行轉化爲集合存儲
{
"$group": {
"_id": null,
"tableA": {
"$push": "$$ROOT"
}
}
},
// 拆分集合爲行,同時帶上數組下標
{
$unwind:{
path:'$tableA',
includeArrayIndex:'arrayIndex'
}
},{
$project:{
'_id':0,
'creatorName':'$tableA.name',
'creatorId':'$tableA.grade',
'arrayIndex':{
$add:['$arrayIndex',1]
}
}
}
])
二、方案2: 同分同排名,排名連續
如:李四、王五 分數一樣,排名: 張三-1,李四-2,王五-2,趙六-3
注:趙六是第三名而不是第四名
實現原理
首先 獲取 分數所在的排名,然後關聯用戶分數表,將用戶的分數與排名關聯上,獲取的就是該用戶的排名
Mongo語句
db.grade.aggregate([
{
// 獲取分數所在排名
$group:{
'_id':'$grade',
'grade':{
$first:'$grade'
}
}
},{
$sort:{'grade':-1}
},{
$group:{
"_id": null,
"tableA": {
"$push": "$$ROOT"
}
}
},{
$unwind:{
path:'$tableA',
includeArrayIndex:'arrayIndex'
}
},{
$project:{
'_id':0,
'grade':'$tableA.grade',
'arrayIndex':{
$add:['$arrayIndex',1]
}
}
},
// 關聯用戶成績表
{
$lookup:{
"from": "grade",
"localField": "grade",
"foreignField": "grade",
"as": "userGrade"
}
},{
$unwind:'$userGrade'
},{
$project:{
'creatorName':'$userGrade.name',
'creatorId':'$userGrade.grade',
'arrayIndex':1
}
}
])
三、 擴展-同分不同排名-獲取當前用戶排名和前n的排名
Mongo語句
db.grade.aggregate([
{
$sort:{
'grade':-1
}
},
// 將行轉化爲集合存儲
{
"$group": {
"_id": null,
"tableA": {
"$push": "$$ROOT"
}
}
},
// 拆分集合爲行,同時帶上數組下標
{
$unwind:{
path:'$tableA',
includeArrayIndex:'arrayIndex'
}
},{
$project:{
'_id':0,
'name':'$tableA.name',
'creatorId':'$tableA.grade',
'arrayIndex':{
$add:['$arrayIndex',1]
}
}
},
// 對同一數據進行兩次不同操作
{
$facet:{
'my':[
{
$match:{
'name':'李四'
}
}
],
// 測試獲取前五的排名
'top':[{
$limit:5
},{
$skip:0
}
]
}
}
])
僅返回一行記錄
字段:my 存儲我的排名是集合
字段:top 存儲前n的排名是集合