Laravel中查询各产品平均评分与评分总数的实现方法
Laravel 产品列表关联获取平均评分、评分总数实现方案
前置准备
首先确保Product模型中已经定义好和Review的一对多关联:
// app/Models/Product.php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Product extends Model { // 其他原有模型配置 public function reviews() { return $this->hasMany(Review::class, 'product_id'); } }
方案1:数据库层聚合查询(生产环境首选,性能最优)
利用Laravel原生的withCount方法自定义聚合字段,全程仅执行2条SQL,无N+1问题,不会加载多余评价数据,性能不受数据量影响。
首先在控制器头部引入DB门面:
use Illuminate\Support\Facades\DB;
查询代码如下:
$products = Product::withCount([ // 统计评分总条数 'reviews as review_total', // 计算平均评分,ROUND保留1位小数可按需调整,COALESCE处理无评价时默认返回0 'reviews as avg_rating' => function ($query) { $query->select(DB::raw('ROUND(COALESCE(AVG(rating), 0), 1)')); } ])->get();
查询结果直接通过对象属性调用即可:
foreach ($products as $product) { // 原有产品字段 $product->id; $product->name; $product->price; // 新增统计字段 $product->review_total; // 该产品评分总条数 $product->avg_rating; // 该产品平均评分 }
方案2:集合层计算(仅适合小数据量场景)
如果项目评价总量很小,可以预加载关联后通过Laravel集合方法计算统计值,缺点是会查询出所有关联的评价记录,数据量大时内存占用极高,不推荐生产环境大数据量场景使用:
$products = Product::with('reviews') ->get() ->map(function ($product) { $product->review_total = $product->reviews->count(); $product->avg_rating = $product->reviews->avg('rating') ?? 0; return $product; });
避坑提示
不要在未预加载关联的情况下,循环遍历产品时单独查询评价统计:
// 错误写法,会产生N+1查询,产品数量越多SQL执行次数越多,性能极差 $products = Product::all(); foreach ($products as $product) { $product->review_total = $product->reviews()->count(); $product->avg_rating = $product->reviews()->avg('rating'); }
内容的提问来源于stack exchange,提问作者Kanak
相关产品推荐
相关产品推荐

