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);
}

 

posted @ 2020-09-10 10:25  带着蚂蚁去散步  阅读(577)  评论(0编辑  收藏  举报