You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中如何筛选平均评分大于等于指定值的项目?

解决Laravel中筛选平均评分≥指定值的项目问题

嘿,我明白你现在的困扰了——想要筛选出平均评分大于等于输入值的项目,但之前的两次尝试都没达到预期效果。我来帮你梳理问题,然后给出正确的实现方式。

为什么之前的尝试失败了?

  • 第一次尝试用whereIn('ratings.star', $filters['reviews']),这是在找包含指定评分星级的项目,而不是计算平均评分后筛选,逻辑完全不对,所以不符合需求。
  • 第二次尝试的问题在于,你在where闭包里直接编写了分组和聚合查询,但没有正确关联主表(items)和子查询的item_id,导致这个条件实际上没有起到筛选作用,自然返回了所有项目。

正确的实现方式

这里有几种可靠的方法,你可以根据自己的需求选择:

方法一:使用whereHas关联查询(最优雅,推荐)

如果你的Item模型已经和Rating模型定义了关联关系(比如Item里有public function ratings() { return $this->hasMany(Rating::class); }),用whereHas可以利用关联直接筛选,代码简洁清晰:

$filters['ratings'] = array_filter($filters['ratings']);
if ($filters['ratings']) {
    $minRating = $filters['ratings']; // 确保这是一个有效的数值,比如4.0
    $this->model = $this->model->whereHas('ratings', function ($query) use ($minRating) {
        $query->groupBy('item_id')
              ->havingRaw('AVG(star) >= ?', [$minRating]);
    });
}

方法二:使用whereExists子查询

如果没有定义关联,或者更倾向于原生子查询写法,可以用whereExists检查每个项目是否存在符合平均评分要求的记录:

use Illuminate\Support\Facades\DB;

$filters['ratings'] = array_filter($filters['ratings']);
if ($filters['ratings']) {
    $minRating = $filters['ratings'];
    $this->model = $this->model
        ->whereExists(function ($query) use ($minRating) {
            $query->select(DB::raw(1))
                ->from('ratings')
                ->whereColumn('ratings.item_id', 'items.id') // 关联主表与评分表的item_id
                ->groupBy('ratings.item_id')
                ->havingRaw('AVG(ratings.star) >= ?', [$minRating]);
        });
}

方法三:使用leftJoin结合分组和having

如果需要在结果中同时返回项目的平均评分,可以用这种方式,同时记得处理无评分的项目(用COALESCE把null转为0):

use Illuminate\Support\Facades\DB;

$filters['ratings'] = array_filter($filters['ratings']);
if ($filters['ratings']) {
    $minRating = $filters['ratings'];
    $this->model = $this->model
        ->leftJoin('ratings', 'ratings.item_id', '=', 'items.id')
        ->select('items.*', DB::raw('AVG(ratings.star) AS average_rating')) // 可选:返回平均评分字段
        ->groupBy('items.id') // 按项目主键分组,避免重复数据
        ->havingRaw('COALESCE(AVG(ratings.star), 0) >= ?', [$minRating]);
}

额外提示

  • 确保$filters['ratings']是有效的数值,比如从请求获取时可以做类型转换:$minRating = (float) $request->input('rating', 0);
  • 如果要包含无评分的项目,可以调整COALESCE的默认值,比如把0改成你需要的最低阈值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 16:57:44