Laravel Eloquent按ambulance_id合并Consumption及关联条目
实现方案
直接在查询后做按ambulance_id的分组合并即可,不要硬改模型关联,避免影响其他业务场景的使用,整套逻辑只需要3条SQL,性能远高于循环单条查询:
首先拉取符合筛选条件的所有消耗记录,按救护车ID分组,每组取第一条作为合并后的返回主体,同时收集所有需要关联查询的消耗记录ID;第二步一次性拉取所有分组汇总后的消耗条目、预加载救护车关联;最后把对应条目挂载到合并后的主记录上就行。
可直接复用的代码如下:
// 拉取符合时间、救护车筛选范围的消耗记录 $filteredConsumptions = Consumption::query() ->whereIn('ambulance_id', $subset) ->whereBetween('document_date', [$old_from_date, $old_until_date]) ->get(['id', 'ambulance_id', 'document_date']); // 按需补充你需要返回的Consumption表字段 $groupedByAmbulance = $filteredConsumptions->groupBy('ambulance_id'); $mergedList = collect(); $allConsumptionIds = collect(); foreach ($groupedByAmbulance as $ambulanceId => $sameAmbulanceRecords) { // 取同组第一条记录作为合并后的返回主体,需要取最早/最新记录的话可以在这里加排序逻辑 $mainRecord = $sameAmbulanceRecords->first(); $mergedList->push($mainRecord); $allConsumptionIds = $allConsumptionIds->merge($sameAmbulanceRecords->pluck('id')); } // 一次性查询所有按item_stock_id分组汇总的消耗条目,避免N+1查询 $groupedItems = ConsumptionItem::query() ->whereIn('consumption_id', $allConsumptionIds) ->select( 'id', 'consumption_id', 'item_id', 'item_stock_id', ConsumptionItem::raw('SUM(quantity) as quantity') ) ->groupBy('item_stock_id') ->get(); // 一次性预加载所有救护车关联信息 $mergedList->load('ambulance'); // 将汇总后的消耗条目挂载到对应合并后的主记录上 foreach ($mergedList as $record) { $currentGroupIds = $groupedByAmbulance->get($record->ambulance_id)->pluck('id'); $record->setRelation( 'consumption_items_grouped', $groupedItems->whereIn('consumption_id', $currentGroupIds)->values() ); } // $mergedList 就是最终需要的结果集
注意点
- 如果你需要指定合并后主记录的选取规则,比如取单据日期最新的记录作为主体,把
$sameAmbulanceRecords->first()改成$sameAmbulanceRecords->sortByDesc('document_date')->first()即可 - 原有模型上的
consumption_items_grouped关联不需要做任何修改,其他单条Consumption查询的场景可以正常使用 - 对应你给出的测试样例:ambulance_id=5下的id1、id2两条记录会合并为单条id1的记录,挂载的消耗条目包含全部4条关联数据,完全符合预期。
内容的提问来源于stack exchange,提问作者Cristian25
相关产品推荐
相关产品推荐

