Laravel的Redis排行榜
场景
- 用户邀请排行榜
users测试表结构
- 基本的数据结构
字段 | 备注 |
id | 用户 id |
name | 昵称 |
invite_count | 邀请人数 |
created_at | 创建时间 |
updated_at | 更新时间 |
代码说明
return $this->response->paginator($data, new UserTransformer())->setMeta($userInfo);
- 使用了Dingo API
- https://learnku.com/docs/dingo-api/2.0.0/Responses/1446
常规的做法
SQL排序 --》存Redis(设置过期时间)
/** * 走数据库 [排行榜] * @return \Dingo\Api\Http\Response */ public function rankingList() { $currentUserId = 1; if (!\Cache::has('ranking-list')) { \Cache::remember('ranking-list', 1, function (){ //laravel5.6是1分钟, laravel5.8之后是1s // 先取排名 return User::selectRaw('id, name, email, invite_count, if(@rowNum,@rowNum := @rowNum +1,@rowNum := 1) as rank_num') ->where('invite_count', '>=', 1) ->orderBy('invite_count', 'desc') ->orderBy('updated_at', 'asc') //invite_count和updated_at建联合索引 ->paginate(); }); } $data = \Cache::get('ranking-list'); // 集合生成数组 $result = $data->pluck('rank_num', 'id')->toArray(); // 用户名次 $currentUser = User::find($currentUserId); $userInfo = [ 'user_id' => $currentUserId, 'user_rank' => $result[$currentUserId] ?? '--', //取用户名次,注意下标没有的情况 'phone' => $currentUser->phone, 'invite_count' => $currentUser->invite_count, ]; return $this->response->paginator($data, new UserTransformer())->setMeta($userInfo); }
利用Zset有序集合
/** * Rides的zSet [排行榜] * $invite_count[邀请次数] , $user_id[用户ID] * @return \Dingo\Api\Http\Response */ public function rankingList() { // 用户创建时记录 zAdd($key, $invite_count, $user_id) // 邀请成功时记录 zIncrBy($key, 1, $user_id) // 查看总的条数 zCard($key) // 查询所有的记录 zRevRange($key, 0, $num-1 , false); // 查看自己的名次 zRevRank($key, $user_id) // 得到排序好的 user_ids $redis_store = \Cache::store('redis'); $store_key = $redis_store->getPrefix(); // 获取前缀 $redis = $redis_store->getRedis(); // 实例化redis $key = $store_key . 'test-ranking-list:'; /** * Mock加数据 */ $users = User::all()->toArray(); foreach ($users as $item){ $redis->zAdd($key, $item['invite_count'], $item['id']); } /** * 总排行(从大到小排序好) */ $user_ids = $redis->zRevRange($key, 0, 9 , false); // 取前10名,全部的话end为num-1,zCard($key) $ids_ordered = implode(',', $user_ids); $rankingBoard = User::whereIn('id', $user_ids) ->orderByRaw(DB::raw("FIELD(id, $ids_ordered)")) // whereIn按user_id排序返回 ->paginate(); /** * 用户所属排名 */ $currentUserId = 1; //当前用户 $rank = $redis->zRevRank($key, $currentUserId); $myInfo = [ 'rank' => $rank + 1, 'user_id' => $currentUserId, ]; return $this->response->paginator($rankingBoard, new UserTransformer())->setMeta($myInfo); }