Laravel Eloquent如何按自定义total_views属性对Product模型查询结果排序
问题原因说明
Laravel 的访问器是在SQL查询完成、模型实例化之后才会生成的属性,orderBy 属于SQL查询阶段的操作,数据库层面根本不存在 total_views 这个字段,所以直接用访问器属性做排序不会生效。同时你原本的访问器实现会存在N+1查询问题,列表查询时每个商品实例都会单独触发一次求和查询,性能很差。
方案1:使用 withCount 实现SQL层面排序(通用推荐)
这是性能最优的通用方案,兼容分页需求,一次查询即可完成所有统计和排序:
use Illuminate\Support\Facades\DB; $products = Product::withCount([ 'views as total_views' => function ($query) { // 统计关联views表count字段的和,IFNULL处理无浏览记录时返回0 $query->select(DB::raw('IFNULL(SUM(count), 0)')); } ]) // 直接对SQL计算出的total_views字段排序 ->orderBy('total_views', 'desc') ->get();
方案2:集合排序(仅适合极小数据量场景)
如果你的商品总数据量小于100条且不需要分页,可以查询出全量数据后用Laravel集合方法排序:
// 查询所有商品后在PHP层面按访问器属性排序 $products = Product::get()->sortByDesc('total_views');
注意该方案缺陷明显:需要将全量数据加载到内存中排序,数据量稍大就会出现性能问题,且无法正常使用分页功能。
方案3:冗余字段优化(高频排序场景推荐)
如果业务中需要频繁按总浏览量排序,建议在products表新增total_views整型字段,通过模型事件/观察者在View模型的新增、更新事件触发时,同步更新对应商品的total_views值,后续排序直接操作实际字段即可,性能最高:
// 排序逻辑简单,查询效率远高于关联统计 $products = Product::orderBy('total_views', 'desc')->paginate(10);
内容的提问来源于stack exchange,提问作者Kali FR
相关产品推荐
相关产品推荐

