You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Eloquent中对关联模型的自定义属性使用聚合函数?

解决Eloquent中自定义属性的聚合计算问题

withAvg这类Eloquent聚合方法是直接生成SQL在数据库层面执行的,只能识别数据库实际存在的字段,没法直接用模型的自定义属性。下面给两种可行的解决思路:

思路一:把自定义属性的计算逻辑移到数据库层面

如果你的duration是基于Command模型的数据库字段计算出来的(比如用start_time和end_time相减得到),直接把计算逻辑写到SQL里就行,两种实现方式:

方式1:用子查询构造平均值计算

$projects = Project::with('tasks.commands')
    ->addSelect([
        'average_duration' => Command::selectRaw('AVG(end_time - start_time)')
            ->whereIn('task_id', function ($query) {
                $query->select('id')->from('tasks')->whereColumn('project_id', 'projects.id');
            })
    ])
    ->get();

方式2:借助HasManyThrough关联

先在Project模型里定义和Command的间接关联:

// Project.php
public function commands()
{
    return $this->hasManyThrough(Command::class, Task::class);
}

然后直接用withAvg,把计算逻辑传入:

$projects = Project::with('tasks.commands')
    ->withAvg('commands', DB::raw('end_time - start_time'))
    ->get();

这样得到的commands_avg_duration就是你要的平均值。

思路二:内存中手动计算(适合数据量小的场景)

如果duration的计算逻辑特别复杂,没法用SQL实现(比如依赖其他自定义属性、外部接口数据),那就只能先把所有数据拉到内存里再计算:

// 加载所有关联数据
$projects = Project::with('tasks.commands')->get();

// 逐个项目计算平均值
$projects->each(function ($project) {
    // 提取所有有效的duration值
    $validDurations = $project->tasks
        ->flatMap(function ($task) {
            return $task->commands->pluck('duration');
        })
        ->filter(); // 过滤掉空值

    // 赋值平均值,空的话设为0避免报错
    $project->average_duration = $validDurations->isEmpty() ? 0 : $validDurations->avg();
});

注意:这种方法会把所有tasks和commands都加载到内存,数据量大的时候性能会受影响,谨慎使用。

内容的提问来源于stack exchange,提问作者vbulash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:57:09