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

Laravel中按order_id分组查询Eloquent关联pivot中间表值的实现方法

问题解答

你可以通过优化Eloquent查询+简单的集合处理实现需求,不需要复杂的额外逻辑。同时你当前的实现存在两处明显问题:

  1. Dish和Restaurant是多对多关联,dishes表不存在restaurant_id字段,你写的Dish::where('restaurant_id', $user_id)逻辑不成立,只有一对多关联才会在子表存父级ID。
  2. 循环获取订单属于典型的N+1查询,数据量稍大就会出现严重性能问题。

优化实现步骤

第一步:先补全Order模型的关联配置

你需要在Order的dishes关联中声明要读取的中间表字段,否则无法获取quantity值:

class Order extends Model
{
    public function dishes()
    {
        return $this->belongsToMany('App\Models\Dish')->withPivot('quantity');
    }
}

第二步:改写控制器查询逻辑

public function index($restaurantId)
{
    $orders = Order::whereHas('dishes.restaurant', function ($query) use ($restaurantId) {
        // 筛选出包含当前餐厅菜品的订单
        $query->where('restaurants.id', $restaurantId);
    })
    ->with(['dishes' => function ($query) use ($restaurantId) {
        // 预加载订单中属于当前餐厅的菜品,过滤其他餐厅的菜品
        $query->whereHas('restaurant', function ($q) use ($restaurantId) {
            $q->where('restaurants.id', $restaurantId);
        });
    }])
    ->get()
    ->unique('id') // 订单去重,避免同一个订单因关联多个菜品被重复返回
    ->map(function ($order) {
        // 整理菜品输出结构
        $order->dishes = $order->dishes->map(function ($dish) {
            return [
                'dish_id' => $dish->id,
                'quantity' => $dish->pivot->quantity
            ];
        });
        return $order;
    })
    ->values();

    return response()->json($orders);
}

以上代码总共只执行3次数据库查询,完全避免了N+1问题,输出结构和你要求的格式完全一致。


这类场景的最佳实践

  • 优先用预加载(with方法) 读取关联数据,绝对不要在循环中执行数据库查询。
  • 多对多关联的条件筛选优先用whereHas实现,比先查关联模型再循环取数的效率高一个数量级。
  • 输出结构统一用Laravel的API资源(API Resource) 管理,不要把结构整理逻辑写在控制器里,后续维护更方便,示例:
// app/Http/Resources/OrderResource.php
class OrderResource extends JsonResource
{
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'status' => $this->status,
            'address' => $this->address,
            'user_name' => $this->user_name,
            'user_surname' => $this->user_surname,
            'phone' => $this->phone,
            'email' => $this->email,
            'total' => $this->total,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
            'dishes' => DishResource::collection($this->whenLoaded('dishes'))
        ];
    }
}

控制器中直接返回资源集合即可:return OrderResource::collection($orders);

  • 如果你的业务逻辑中一个菜品仅属于一个餐厅,建议把Dish和Restaurant的关联改成一对多(Dish表加restaurant_id字段,关联改成belongsTo),查询效率会更高,逻辑也更清晰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 11:54:06