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

如何使用Eloquent获取两层hasMany关联的列求和结果

使用Eloquent获取两层hasMany关联的列总和

可以通过Laravel Eloquent的withSum方法实现需求,无需手动编写原生SQL或JOIN语句,框架会自动处理关联聚合逻辑。

1. 确认模型关联

确保你的模型已经正确定义层级关联:

Faction 模型

// app/Models/Faction.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Faction extends Model
{
    public function islands()
    {
        return $this->hasMany(Island::class);
    }
}

Island 模型

// app/Models/Island.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Island extends Model
{
    public function shrines()
    {
        return $this->hasMany(Shrine::class);
    }
}

Shrine 模型

// app/Models/Shrine.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Shrine extends Model
{
    // 保持基础模型结构即可,无需额外关联定义
}

2. 执行聚合查询

使用withSum指定嵌套关联(islands.shrines)和需要求和的字段(points),再将结果转换为你需要的格式:

$factions = Faction::withSum('islands.shrines', 'points')
    ->get()
    ->map(fn($faction) => [
        'id' => $faction->id,
        'points' => $faction->islands_shrines_sum_points ?? 0
    ])
    ->toArray();

结果说明

  • withSum会自动生成名为islands_shrines_sum_points的属性,存储对应派系的神社点数总和
  • 使用?? 0处理无关联神社的派系,避免返回null值
  • 最终输出完全匹配你期望的结构:
    [
        ['id' => 1, 'points' => 300], 
        ['id' => 2, 'points' => 340],
        ['id' => 3, 'points' => 200],
    ]
    

备选方案(性能较低,仅适用于小数据量)

如果需要在模型中直接访问总和,可以定义访问器,但该方式会触发N+1查询:

// 在Faction模型中添加访问器
public function getTotalPointsAttribute()
{
    return $this->islands->sum(fn($island) => $island->shrines->sum('points'));
}

// 使用方式
$factions = Faction::with('islands.shrines')
    ->get()
    ->map(fn($faction) => [
        'id' => $faction->id,
        'points' => $faction->total_points
    ])
    ->toArray();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 20:15:33