Laravel Eloquent:获取仅关联单个指定子项的父级数据并求和
解决Laravel中筛选特定关联且仅单关联的项目求和问题
嘿,我明白你现在的需求:要找出只关联了特定ID的PaisBeneficiario,而且本身仅关联一个子项的Proyectos,然后把这些项目的monto_aprobado加起来。之前用嵌套foreach确实太麻烦,而且你写的那段代码没拿到预期结果,问题出在没正确处理多对多关联的筛选条件,我来给你捋清楚怎么高效实现。
先理清楚你的问题根源
你之前写的Proyecto::all()->where('pais_beneficiarios', $id)是错误的:
pais_beneficiarios是模型的关联关系,不是proyectos表的字段,直接用where查这个"字段"根本找不到数据- 这段代码也完全没处理"仅关联一个子项"的条件,自然得不到正确结果
先再确认下你的模型关联(方便后续理解解决方案):
Proyectos模型
public function pais_beneficiarios() { return $this->belongsToMany(\App\Models\PaisBeneficiario::class, 'pais_beneficiario_proyecto', 'id_proyecto', 'id_pais_beneficiario')->withPivot('monto_beneficio'); }
PaisBeneficiario模型
public function pais_beneficiario() { return $this->belongsTo(\App\Models\PaisBeneficiario::class, 'id_pais_beneficiario'); } public function proyecto() { return $this->belongsTo(\App\Models\Proyecto::class, 'id_proyecto'); }
PaisBeneficiarioProyectos模型
public function proyectos() { return $this->belongsToMany(\App\Models\Proyecto::class, 'pais_beneficiario_proyecto', 'id_pais_beneficiario', 'id_proyecto')->withPivot('monto_beneficio'); }
高效解决方案:用Laravel关联查询+聚合
不需要嵌套循环,直接通过数据库层面的筛选和聚合就能搞定,两种方法都可以:
方法一:用whereHas+has快速约束
这是最简洁的写法,直接利用Laravel的关联计数约束:
$targetPaisId = $id; // 你要筛选的特定PaisBeneficiario ID $montoTotal = Proyecto::query() // 第一步:筛选关联了目标ID的PaisBeneficiario的项目 ->whereHas('pais_beneficiarios', function ($query) use ($targetPaisId) { $query->where('id_pais_beneficiario', $targetPaisId); }) // 第二步:筛选仅关联1个PaisBeneficiario的项目 ->has('pais_beneficiarios', '=', 1) // 最后直接对符合条件的项目求和 ->sum('monto_aprobado');
代码解释:
whereHas:用来过滤存在指定关联条件的模型,这里确保项目确实关联了你指定ID的PaisBeneficiariohas('pais_beneficiarios', '=', 1):直接约束项目的关联数量恰好为1,完美满足"仅关联一个子项"的要求sum('monto_aprobado'):Laravel会自动生成聚合SQL,让数据库直接计算总和,比把所有数据拉到内存里再求和高效太多
方法二:用withCount+having更灵活计数
如果你的场景需要更精细的关联统计(比如从中间表维度确认数量),可以用这种写法:
$montoTotal = Proyecto::query() ->whereHas('pais_beneficiarios', function ($query) use ($targetPaisId) { $query->where('id_pais_beneficiario', $targetPaisId); }) // 给项目添加关联数量的统计字段 ->withCount('pais_beneficiarios') // 约束统计数量等于1 ->having('pais_beneficiarios_count', '=', 1) ->sum('monto_aprobado');
这两种方法都能完美满足你的需求,而且性能比嵌套foreach好很多,所有逻辑都在数据库层面完成,避免了不必要的内存消耗。
内容的提问来源于stack exchange,提问作者Diego Alejandro Lopez
相关产品推荐
相关产品推荐

