我在 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
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);
});
});
我还没有测试过这个,所以如果有问题请告诉我,我会更新答案。
虽然链接嵌套方法负载来尝试构建“纯 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()
);