如何在Eloquent多表关联中统计各群组的用户数量?
嗨,我来帮你搞定这个群组用户数统计的需求!
首先看你的原代码,你现在是查询当前用户加入的所有群组,但想要给每个群组加上对应的总用户数对吧?我给你两种方案,一种是基于你现有join方式修改,另一种是更符合Eloquent风格的关联查询方式。
方案一:基于现有Join查询修改
你只需要调整select字段,添加统计语句,再加上groupBy就可以了:
use Illuminate\Support\Facades\DB; $result = UserHasGroup::join('group', 'user_has_group.group_id', '=', 'group.id') ->join('user', 'group.created_by', '=', 'user.id') ->where('user_has_group.user_id', '=', $user->id) ->select( "user.name as created_by", 'group.created_at', 'group.name as group_name', 'group.id as group_id', // 统计每个群组的唯一用户数,用DISTINCT避免重复计数(比如用户重复关联的情况) DB::raw('COUNT(DISTINCT user_has_group.user_id) as user_count') ) // 按群组的唯一ID和其他非聚合字段分组,避免严格模式下报错 ->groupBy('group.id', 'user.name', 'group.created_at', 'group.name') ->get();
关键点说明:
- 用
DB::raw()来编写统计逻辑,因为Eloquent的select方法直接处理聚合函数需要原生SQL支持 groupBy里必须包含所有非聚合的字段(也就是你select里除了count之外的所有字段),不然MySQL在严格模式下会抛出错误- 用
DISTINCT包裹user_id是为了防止同一个用户被多次统计(比如如果user_has_group表里有重复的关联记录)
方案二:用Eloquent关联关系实现(更优雅)
其实Eloquent本身的关联功能可以让代码更简洁,先给你的模型定义好关联:
第一步:定义模型关联
在Group模型里添加两个关联方法:
// Group.php public function users() { // 群组和用户是多对多关系,中间表是user_has_group return $this->belongsToMany(User::class, 'user_has_group'); } public function creator() { // 群组的创建者是用户,关联字段是created_by return $this->belongsTo(User::class, 'created_by'); }
第二步:编写查询代码
$result = Group::whereHas('users', function($query) use ($user) { // 筛选当前用户加入的群组 $query->where('user_id', $user->id); }) ->withCount('users') // 自动统计每个群组的用户数,生成users_count字段 ->with('creator') // 预加载创建者信息,避免N+1查询 ->select('id', 'name as group_name', 'created_at') ->get() // 整理成你需要的返回格式 ->map(function($group) { return [ 'created_by' => $group->creator->name, 'created_at' => $group->created_at, 'group_name' => $group->group_name, 'user_count' => $group->users_count ]; });
这个方案的优势是代码更易读,也不需要手动处理join和groupBy,Eloquent会帮你自动生成正确的SQL。
两种方案最终返回的结果都会包含user_count字段,对应每个群组的用户总数,比如:
{ "successful": [ { "created_by": "TUSHAR13", "created_at": "2018-05-11 18:04:38", "group_name": "DSGJA", "user_count": 3 }, { "created_by": "TUSHAR13", "created_at": "2018-05-11 18:10:17", "group_name": "V76OL", "user_count": 5 } ] }
内容的提问来源于stack exchange,提问作者Tushar Monirul




