Laravel如何反转关联输出 获取指定结构的最近仓库关联产品数据
解决方案
前置优化:先查询最近仓库ID(性能优化)
先单独查询最近的仓库ID,避免嵌套在闭包中重复查询,同时提前处理无仓库的异常场景:
// 提取最近仓库ID $nearestWarehouseId = Warehouse::orderByDistance('location', new Point($req->query('lat'), $req->query('lng'))) ->value('id'); if (!$nearestWarehouseId) { // 无匹配仓库时自行处理返回逻辑 return response()->json([]); }
方案1:无需改模型,直接用集合整理输出结构(最简方案)
不需要调整现有模型关联,直接对查询结果做集合格式化,就能得到你要的结构:
$products = Product::whereHas('warehouses', static function ($q) use ($nearestWarehouseId) { $q->where('warehouses.id', $nearestWarehouseId); }) ->with('feature_values.feature') ->paginate() // 遍历分页数据整理结构 ->through(function ($product) { // 按特征分组当前产品的所有特征值 $groupedFeatures = $product->feature_values->groupBy('feature_id')->map(function ($featureValues) { $feature = $featureValues->first()->feature; return [ 'id' => $feature->id, 'name' => $feature->name, 'feature_values' => $featureValues->map(fn($v) => [ 'id' => $v->id, 'value' => $v->value ]) ]; })->values(); // 替换关联结构 unset($product->feature_values); $product->features = $groupedFeatures; return $product; });
方案2:通过API资源标准化输出(更推荐,可维护性高)
如果需要长期维护这个输出结构,用Laravel自带的API资源做格式管控更稳妥:
- 生成对应资源类
php artisan make:resource ProductResource php artisan make:resource FeatureResource php artisan make:resource FeatureValueResource
- 编辑
app/Http/Resources/FeatureValueResource.php
public function toArray($request) { return [ 'id' => $this->id, 'value' => $this->value ]; }
- 编辑
app/Http/Resources/FeatureResource.php
public function toArray($request) { return [ 'id' => $this->id, 'name' => $this->name, 'feature_values' => FeatureValueResource::collection($this->feature_values) ]; }
- 编辑
app/Http/Resources/ProductResource.php
public function toArray($request) { // 先按特征分组特征值 $groupedFeatures = $this->feature_values->groupBy('feature_id')->map(function ($values) { return new FeatureResource($values->first()->feature->setRelation('feature_values', $values)); })->values(); return [ 'id' => $this->id, 'name' => $this->name, 'price' => $this->price, 'features' => $groupedFeatures ]; }
- 控制器最终返回
$products = Product::whereHas('warehouses', static function ($q) use ($nearestWarehouseId) { $q->where('warehouses.id', $nearestWarehouseId); }) ->with('feature_values.feature') ->paginate(); return ProductResource::collection($products);
内容的提问来源于stack exchange,提问作者bassel5511
相关产品推荐
相关产品推荐

