如何以雄辩的关系对透视表列进行分组和求和?

问题描述 投票:9回答:3

在Laravel 4中;我有模型ProjectPart,它们与数据透视表project_part具有多对多关系。数据透视表的列count包含项目中使用的零件ID的编号,例如:

id  project_id  part_id count
24  6           230     3

[这里project_id 6,正在使用3个part_id 230。

一个项目可能多次列出一个部分,例如:

id  project_id  part_id count
24  6           230     3
92  6           230     1

当我显示项目的零件清单时,我不想重复显示part_id,因此我将结果分组。

我的[[Projects模型具有此:

public function parts() { return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id') ->withPivot('count') ->withTimestamps() ->groupBy('pivot_part_id') }
但是我的count值当然不正确,这是我的问题:

如何获得项目的所有分组部分的总和?

意味着我的project_id 6零件清单应类似于:

part_id count 230 4

我非常想以Projects-Parts关系使用它,因此我急切地希望加载它。

如果不解决N + 1问题,我将不知所措,我们将不胜感激。


更新:

作为临时的解决方法,我创建了一个presenter方法来获取项目中的总零件数。但这给了我N + 1的问题。public function sumPart($project_id) { $parts = DB::table('project_part') ->where('project_id', $project_id) ->where('part_id', $this->id) ->sum('count'); return $parts; }
laravel laravel-4 eloquent relationships
3个回答
8
投票
code source

我们需要为所有枢轴列都加上别名“ pivot_”,以便我们可以轻松地将它们从模型中提取出来,并在将它们检索并合并到模型中后置于枢轴关系中。

因此您可以使用select方法执行相同操作

public function parts() { return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id') ->selectRaw('parts.*, sum(project_part.count) as pivot_count') ->withTimestamps() ->groupBy('project_part.pivot_part_id') }


18
投票
尝试在Collection中求和,

$project->parts->sum('pivot.count');

这是我发现的最好方法。它很干净(易于阅读),并且可以在parts多对多定义中重新使用所有范围,顺序和关系属性缓存。

@ hebron如果使用with('parts')eager load,则此解决方案没有N + 1问题。由于$project->parts

without函数调用)是缓存的属性,因此请返回Collection的实例以及所有数据。 sum('pivot.count')Collection的一种方法,它包含纯函数助手(与js world中的underscore无关,与数据库无关)。

完整示例:

相关部分的定义:

class Project extends Model { public function parts() { return $this->belongsToMany('Part', 'project_part', 'project_id', 'part_id') ->withPivot('count') ->withTimestamps(); } }

[使用时(注意,急切的加载对于避免N + 1问题很重要),

App\Project::with('parts')->get()->each(function ($project) { dump($project->parts->sum('pivot.count')); });

或者您可以在Project.php中定义sum函数,

class Project extends Model { ... /** * Get parts count. * * @return integer */ public function partsCount() { return $this->parts->sum('pivot.count'); } }

如果要避免在呼叫方使用with('parts')(默认情况下为紧急加载部分,则可以添加$with属性

class Project extends Model { /** * The relations to eager load on every query. * * @var array */ protected $with = ['parts']; ... }


0
投票
最好的使用方法是:

$project->parts->sum('pivot.count');

我遇到了同样的问题,但这解决了我的问题。
© www.soinside.com 2019 - 2024. All rights reserved.