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

Laravel如何将相同measured_at日期的关联数据归组到同一数组

问题描述

调用嵌套关联获取数据时,需要将所有measured_at日期相同的数据归到同一个子数组中,而非分散存储。

当前返回的数据结构

{
    "id": 1,
    "user_body_sizes": [
        {
            "id": 23,
            "measured_at": "2023-04-04"
        },
        {
            "id": 24,
            "measured_at": "2023-04-04"
        },
        {
            "id": 26,
            "measured_at": "2023-03-14"
        },
        {
            "id": 29,
            "measured_at": "2023-03-14"
        }
    ]
}

期望的数据结构

{
    "id": 1,
    "user_body_sizes": [
        [
            {
                "id": 23,
                "measured_at": "2023-04-04"
            },
            {
                "id": 24,
                "measured_at": "2023-04-04"
            }
        ],
        [
            {
                "id": 29,
                "measured_at": "2023-03-14"
            },
            {
                "id": 26,
                "measured_at": "2023-03-14"
            }
        ]
    ]
}

当前代码实现

控制器方法

public function GetCustomerBodySize($customerId, $month, $year)
{
    $customerUserId = Customer::findOrFail($customerId)['user'];

    return CustomerBodySize::with([ 'customer_data.user_body_sizes.body_parts','customer_data.user_body_sizes' => function ($q) use ($month, $year){
        $q->whereMonth('measured_at', '=', $month);
        $q->whereYear('measured_at', '=', $year);
        $q->orderBy('measured_at');
    }])
        ->whereRelation('customer_data', 'id', $customerUserId)
        ->first();
}

模型关联

CustomerBodySize模型

function customer_data(){
    return $this->belongsTo(User::class, 'customer');
}

function body_parts(){
    return $this->belongsTo(BodyParts::class, 'body_part');
}

User模型

public function user_body_sizes(){
    return $this->hasMany(CustomerBodySize::class, 'customer');
}
解决方案

方法一:查询结果后直接分组处理

在获取数据后,利用Laravel集合的groupBy方法按measured_at分组,再转换为目标结构:

public function GetCustomerBodySize($customerId, $month, $year)
{
    $customerUserId = Customer::findOrFail($customerId)['user'];

    $data = CustomerBodySize::with([ 
        'customer_data.user_body_sizes.body_parts',
        'customer_data.user_body_sizes' => function ($q) use ($month, $year){
            $q->whereMonth('measured_at', '=', $month);
            $q->whereYear('measured_at', '=', $year);
            $q->orderBy('measured_at');
        }
    ])
    ->whereRelation('customer_data', 'id', $customerUserId)
    ->first();

    // 对user_body_sizes按日期分组并替换原属性
    if ($data && $data->customer_data->user_body_sizes) {
        $grouped = $data->customer_data->user_body_sizes->groupBy('measured_at')->values()->toArray();
        $data->customer_data->user_body_sizes = $grouped;
    }

    return $data;
}

方法二:添加模型访问器(复用性更高)

如果需要在多个地方使用分组后的结构,可以在User模型中定义访问器:

// User模型中新增访问器
public function getGroupedUserBodySizesAttribute()
{
    return $this->user_body_sizes->groupBy('measured_at')->values()->toArray();
}

然后在控制器中调用该访问器替换原属性:

public function GetCustomerBodySize($customerId, $month, $year)
{
    $customerUserId = Customer::findOrFail($customerId)['user'];

    $data = CustomerBodySize::with([ 
        'customer_data.user_body_sizes.body_parts',
        'customer_data.user_body_sizes' => function ($q) use ($month, $year){
            $q->whereMonth('measured_at', '=', $month);
            $q->whereYear('measured_at', '=', $year);
            $q->orderBy('measured_at');
        }
    ])
    ->whereRelation('customer_data', 'id', $customerUserId)
    ->first();

    if ($data && $data->customer_data) {
        $data->customer_data->user_body_sizes = $data->customer_data->grouped_user_body_sizes;
    }

    return $data;
}

关键逻辑说明

  • groupBy('measured_at'):将集合按日期字段分组,生成以日期为键、对应数据集合为值的分组结果
  • values():移除分组后的键名,只保留数据集合的有序数组
  • toArray():将Laravel集合转换为普通数组,得到目标二维数组结构

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 01:45:27