You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

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次数据库查询),用户量稍大就会拖垮数据库性能。这里给你一套优化方案:

优化方案:一次性查询+分组处理

先一次性把所有用户的tododone数据查出来,再按用户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),性能会提升非常明显。

另外补充:如果你的tododone是用户的关联模型(比如用户有很多待办事项和已完成事项),还可以用**预加载(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

火山引擎 最新活动