You need to enable JavaScript to run this app. Laravel用Eloquent实现多态关联浏览量按分类分组统计的方法
优惠活动
大模型
产品
解决方案
定价
更多

Laravel用Eloquent实现多态关联浏览量按分类分组统计的方法

Eloquent 等价实现方案

方案1:与原生SQL逻辑完全对齐的查询写法

直接通过查询构建器复现原SQL的逻辑链路,每一步与原SQL对应:

$categoryTotalViews = Post::query()
    // 关联所属分类表,对应LEFT JOIN categories逻辑
    ->leftJoin('categories', 'categories.id', '=', 'posts.category_id')
    // 关联浏览量表,对应LEFT JOIN views逻辑
    ->leftJoin('views', function ($join) {
        $join->on('views.viewable_id', '=', 'posts.id')
            // 匹配多态关联的类型约束,锁定Post类型的浏览记录
            ->where('views.viewable_type', Post::class);
    })
    // 按分类ID分组,避免重名分类导致的统计偏差
    ->groupBy('categories.id', 'categories.title')
    // 指定返回字段和统计值
    ->selectRaw(
        'categories.title AS category,
        COUNT(views.id) AS totalViews'
    )
    ->get();

相比你提供的原生SQL,这里把views.viewable_type的判断放到了JOIN闭包内,而非WHERE条件中。原写法会导致LEFT JOIN views退化为INNER JOIN,最终无法返回没有任何浏览记录的分类(这类分类的totalViews会被过滤掉),调整后逻辑更严谨。

方案2:基于关联链路的Eloquent优雅写法

不需要手写Join逻辑,直接利用模型间已定义的关联完成统计。首先在Category模型中补充对应反向关联:

class Category extends Model
{
    // 对应Post模型中belongsTo(Category)的反向关联
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

之后直接使用Laravel内置的关联聚合方法完成查询:

$categoryTotalViews = Category::query()
    // 自动沿Category -> Post -> View的关联链路,统计每个分类下所有浏览记录的总和
    ->withSum('posts.views as totalViews')
    // 指定返回字段
    ->select('title as category', 'totalViews')
    ->get();

该写法由Eloquent自动处理多态关联的类型匹配、表关联、分组逻辑,生成的查询结果与手写逻辑等价,维护成本更低。

注意事项

  • 分组统计时必须以categories.id作为分组主键,不要仅按分类名称分组,避免不同分类重名导致的统计合并错误。
  • 所有非聚合的查询字段必须包含在GROUP BY子句中,适配MySQL严格模式的校验规则,避免出现非预期的结果偏差。

内容的提问来源于stack exchange,提问作者Andreas Hunter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.25 21:45:08