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

Laravel Eloquent如何按关联关系分组加载关联数据?

如何用Eloquent按关联字段分组预加载数据?

嘿,我完全懂你想要的效果——把关联的订单按shop_id分成嵌套的键值对,而不是平铺的订单数组。你之前尝试的在预加载闭包里用groupBy()其实走偏了,因为数据库层面的groupBy是用来做聚合计算(比如统计数量、求和)的,不是用来把同组的所有记录归集到一起,所以才会返回普通的订单列表。

下面给你两种用Eloquent实现需求的优雅方式:

方法一:利用模型访问器(最推荐)

在Customer模型里定义一个自定义访问器,自动把预加载的订单按shop_id分组:

class Customer extends Model
{
    // 定义一对多关联
    public function orders()
    {
        return $this->hasMany(Order::class);
    }

    // 自定义访问器:返回按shop_id分组的订单
    public function getOrdersGroupedByShopIdAttribute()
    {
        // 这里用的是Eloquent集合的groupBy,不是数据库的groupBy!
        return $this->orders->groupBy('shop_id');
    }
}

查询时只需要正常预加载订单,之后直接调用访问器即可:

$customer = Customer::with('orders')->find($id);

// 拿到你想要的结构:shop_id => [order1, order2...]
$groupedOrders = $customer->orders_grouped_by_shop_id;

方法二:查询后直接处理集合

如果不想修改模型,也可以在获取数据后直接用Eloquent集合的groupBy方法处理:

// 先预加载所有订单
$customer = Customer::with('orders')->find($id);

// 直接对订单集合分组
$groupedOrders = $customer->orders->groupBy('shop_id');

如果要批量处理多个客户,还可以结合map方法:

$customers = Customer::with('orders')->get()->map(function ($customer) {
    $customer->grouped_orders = $customer->orders->groupBy('shop_id');
    // 可选:移除原始订单数组节省内存
    unset($customer->orders);
    return $customer;
});

为什么你原来的代码不行?

再强调一下:你用的$query->groupBy('shop_id')是数据库层面的分组,它会让数据库返回每个shop_id的一条记录(通常配合聚合函数使用,比如count(*)),而不是把该shop_id下的所有订单都返回。而我们需要的是PHP层面的集合分组,Eloquent的集合类已经内置了这个功能,正好匹配你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:22:37