Laravel Eloquent 对 groupBy 之后的元素求和

问题描述 投票:0回答:2

我在 Laravel 中有一个两级组,想要对每个最终组的金额求和。

模型类似于:

Plan
=====================
id | user_id | game_id | option | amount

我的查询是:

$allbets = DB::table('plan')
            ->select('plan.amount', 'plan.option', 'users.name')
            ->join('users', 'plan.user_id', '=', 'users.id')
            ->where(['plan.game_id' => $game->id])
            ->get()
            ->groupBy('name')
            ->map(function ($option) {
                return $option
                    ->groupBy('option');
            })
        ;

我需要总结每个二级“选项”组的“金额”。 实际结果是:

username1 =>
   option1 =>
      0 =>
          username1
          option1
          10
      1 =>
          username1
          option1
          12

username2 =>
   option1 =>
      0 =>
          username2
          option1
          10
      1 =>
          username1
          option1
          12
   option2 =>
      0 =>
          username2
          option2
          5
      1 =>
          username1
          option2
          6

我需要这个结果:

username1 =>
   option1 =>
          22

username2 =>
   option1 =>
          22
   option2 =>
          11

laravel group-by eloquent sum
2个回答
1
投票

您可以使用laravel

reduce()
方法https://laravel.com/docs/5.7/collections#method-reduce.

在你的地图函数中,在 group by 之后添加reduce,如下所示:

->map(function ($option) {
    return $option
        ->groupBy('option')
        ->map(function($group) {
           // Loop through each group and reduce them.
           $group->reduce(function($carry, $item) {
                // Assume that we always want the last value by using php end() function on array.
                return $carry + end($item);
           }, 0);
        });

});

我还没有测试过这个,所以如果有问题请告诉我,我会更新答案。


0
投票

虽然链接嵌套方法负载来尝试构建“纯 Laravel”解决方案可能很可爱,但最好在数据库级别进行分组和求和并跳过所有多余的映射和分组调用;只需使用

reduce()
进行分组和求和即可。

代码:(PHPize演示

var_export(
    $db::table('plan')
    ->selectRaw('users.name, plan.option, SUM(plan.amount) amount')
    ->join('users', 'plan.user_id', '=', 'users.id')
    ->where(['plan.game_id' => $game->id])
    ->groupBy('name', 'option')
    ->get()
    ->reduce(
        function($result, $row) {
            $result[$row->name][$row->option] = ($result[$row->name][$row->option] ?? 0) + $row->amount;
            return $result;
        }
    )
);

输出:

array (
  'username1' => 
  array (
    'option1' => 22,
  ),
  'username2' => 
  array (
    'option2' => 11,
    'option1' => 22,
  ),
)

如果您对方法链接的重视程度高于时间复杂度,那么以“sym() 调用为目标的列结尾的一对

groupBy()
map()
调用将提供与上面相同的关联 2d 结果。 (PHPize 演示)

var_export(
    $db::table('plan')
    ->select('plan.amount', 'plan.option', 'users.name')
    ->join('users', 'plan.user_id', '=', 'users.id')
    ->where(['plan.game_id' => $game->id])
    ->get()
    ->groupBy('name')
    ->map(
        fn($names) => $names
            ->groupBy('option')
            ->map(
                fn($options) => $options->sum('amount')
            )
    )
    ->toArray()
);
© www.soinside.com 2019 - 2024. All rights reserved.