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
相关产品推荐
相关产品推荐

