Laravel中如何将多SQL请求生成的二维数组转换为Collection
如何将二维数组转为Laravel Collection并优化你的查询逻辑
首先解决你最直接的需求:把二维数组转换成Laravel Collection,其实Laravel提供了超便捷的方式——用collect()辅助函数:
// 假设$yourTwoDimensionalArray是你的目标二维数组 $userCollection = collect($yourTwoDimensionalArray);
如果你的二维数组里的每一项都是用户的原始数据,想要把它们转换成Eloquent模型实例(这样就能直接调用模型的关联、自定义方法等),可以用这两种方式:
- 快速生成模型集合:
$userModels = User::hydrate($yourTwoDimensionalArray);
- 手动转换(适合需要额外处理数据的场景):
$userModels = collect($yourTwoDimensionalArray)->map(function ($userData) { return new User($userData); });
接下来必须提一句你当前代码里的性能隐患:在foreach里循环每个用户并执行两次Eloquent查询,这会触发严重的N+1查询问题(用户数量为N,就会执行2N+1次数据库查询),用户量稍大就会拖垮数据库性能。这里给你一套优化方案:
优化方案:一次性查询+分组处理
先一次性把所有用户的todo和done数据查出来,再按用户ID分组,最后遍历用户时直接从分组后的集合中取数据:
// 第一步:先拿到所有用户的ID(如果$users已经是集合,直接pluck即可) $userIds = collect($users)->pluck('id')->toArray(); // 第二步:一次性查询所有用户的todo数据,并按用户ID分组 $allTodos = User::select('users.id', 'dureeformation') // 只选需要的字段,减少数据传输量 ->whereIn('users.id', $userIds) ->where(/* 这里放你的todo专属查询条件,比如状态为未完成 */) ->get() ->groupBy('id'); // 按用户ID分组,key是用户ID,value是该用户的所有todo集合 // 第三步:同理一次性查询所有用户的done数据并分组 $allDones = User::select('users.id', 'dureeformation') ->whereIn('users.id', $userIds) ->where(/* 这里放你的done专属查询条件,比如状态为已完成 */) ->get() ->groupBy('id'); // 第四步:遍历用户时直接从分组集合取数据 foreach ($userModels as $user) { // 用get()方法获取,第二个参数是默认值(空集合),避免不存在时报错 $userTodos = $allTodos->get($user->id, collect()); $userDones = $allDones->get($user->id, collect()); // 直接用Collection的sum方法,不需要转toBase() $totalTimes = $userTodos->sum('dureeformation'); $spendTimes = $userDones->sum('dureeformation'); $remainingTime = $totalTimes - $spendTimes; // 你的其他业务逻辑... }
这样一来,不管有多少用户,只需要执行3次查询(获取用户、获取所有todo、获取所有done),性能会提升非常明显。
另外补充:如果你的todo和done是用户的关联模型(比如用户有很多待办事项和已完成事项),还可以用**预加载(Eager Loading)**来优化,代码更简洁:
// 假设User模型里有todo()和done()两个关联方法 $userModels = User::whereIn('id', $userIds) ->with(['todo' => function ($query) { $query->select('user_id', 'dureeformation'); // 只选需要的字段 }, 'done' => function ($query) { $query->select('user_id', 'dureeformation'); }]) ->get(); // 遍历的时候直接用关联属性 foreach ($userModels as $user) { $totalTimes = $user->todo->sum('dureeformation'); $spendTimes = $user->done->sum('dureeformation'); $remainingTime = $totalTimes - $spendTimes; }
内容的提问来源于stack exchange,提问作者davidvera




