如何使用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
相关产品推荐
相关产品推荐

