Laravel 9中如何对对象数组排序并将最小值追加至父数组
问题描述
现有接口返回结构:
[{ "id":7, "name": "Product Name", "versions":[ { "id":1, "amount":199 }, { "id":2, "amount":99 } ] }]
Laravel控制器代码:
$q = Product::select('*')->with('getProductVersion'); $product = $q->WhereHas('getProductVersion', function($q){ $q->orderBy('amount', 'asc'); })->get(); return $product;
其中getProductVersion是Product与Version的多对多关联。当前代码无法实现预期效果:
- 关联的
versions数组未按amount升序排列 - 需要在Product对象中新增
lowest_amount字段,存储对应versions里的最小amount值
预期返回结构:
[{ "id":7, "name": "Product Name", "lowest_amount": 99, "versions":[ { "id":2, "amount":99 }, { "id":1, "amount":199 } ] }]
解决方案
1. 修正关联排序问题
WhereHas里的orderBy只是用于筛选关联存在的查询条件,不会影响关联模型的返回顺序。要给关联的versions排序,需要在with方法中传入闭包指定排序规则:
$q = Product::select('*') ->with(['getProductVersion' => function ($query) { $query->orderBy('amount', 'asc'); // 给关联的versions按amount升序排序 }]);
2. 添加lowest_amount字段
使用Laravel的withAggregate方法可以高效从关联模型中聚合出最小值,无需额外遍历处理:
$product = $q->WhereHas('getProductVersion') ->withAggregate('getProductVersion', 'amount', 'min', 'lowest_amount') // 自定义生成lowest_amount字段 ->get();
注:如果不指定第四个参数,Laravel会自动生成
get_product_version_amount_min格式的字段名,按需选择即可。
完整控制器代码
$product = Product::select('*') ->with(['getProductVersion' => function ($query) { $query->orderBy('amount', 'asc'); }]) ->WhereHas('getProductVersion') ->withAggregate('getProductVersion', 'amount', 'min', 'lowest_amount') ->get(); return $product;
可选:在关联定义中默认排序
如果希望每次获取getProductVersion关联时都自动排序,可以在Product模型的关联方法中直接添加排序规则:
public function getProductVersion() { return $this->belongsToMany(Version::class)->orderBy('amount', 'asc'); }
这样控制器中只需写with('getProductVersion'),无需重复定义排序闭包。
内容的提问来源于stack exchange,提问作者Boheman
相关产品推荐
相关产品推荐

