Laravel中如何将多SQL请求生成的二维数组转换为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) {