You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在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

火山引擎 最新活动