【发布时间】:2023-03-06 09:45:01
【问题描述】:
我有两个模型。 Expense 和 Method。我想为每个method type 获取所有expenses 中的sum。我有四种类型:
- bank
- credit-card
- wallet
- savings
每个费用都属于一个方法,每个方法都有许多费用。所以这是一个一对多的关系。因此,每个费用都会存储一个method_id。
以下查询用于获取具有bank 类型的方法的所有费用的总和,例如:
$type = 'bank';
$expenses = auth()->user()->expenses()->with('method')->whereHas('method', function ($query) use ($type) {
$query->where('type', $type);
})->sum('amount');
但问题是,如果我想获得每种方法类型的所有费用总额,我将不得不运行太多查询。我宁愿只获取所有费用,然后过滤它们以获得每种方法类型的所有费用的总和。
以下示例不起作用:
$expenses = auth()->user()->expenses()->with('method')->get();
$bank_balance = $expenses->filter(function ($expense)
{
$expense->whereHas('method', function ($query) {
$query->where('type', 'bank');
})->get(); // with or without ->get()
});
任何想法如何通过不使用太多查询来获得我想要的东西?
编辑:
我没有接受选择的答案,因为它最终没有给我我需要的东西。在我看来,我需要能够做这样的事情:
{{ $bank_balance }}
这意味着,对于 xyz 的回答,我无法做到这一点,因为我无法区分它们。我只根据method_id得到结果,但我需要能够通过方法名称来区分它们。
DigitalDrifter 的答案几乎可以解决问题,但它给了我这个:
Collection {#800 ▼
#items: array:3 [▼
"bank" => Collection {#797 ▼
#items: array:30 [▼
0 => array:2 [▼
"type" => "bank"
"amount" => 1536
]
1 => array:2 [▶]
2 => array:2 [▶]
3 => array:2 [▶]
4 => array:2 [▶]
5 => array:2 [▶]
]
}
"credit-card" => Collection {#798 ▶}
"wallet" => Collection {#799 ▶}
]
}
我基本上需要像这样简单的东西:
"bank" => "此处为所有具有 'bank' 方法的费用的总和" "credit-card" => "这里所有使用‘credit-card’方法的费用的总和”
等等..
我认为->groupBy('type')->each->sum('amount') 这个位可以解决问题,但并不完全。它确实按类型分组,但没有为每种类型提供总和,如您在上面的集合示例中所见。
【问题讨论】:
-
通过 xyz 的回答,您可以访问
$expenses->firstWhere('method.type', 'bank')->amount,不是吗?只需确保在 select 语句中包含 method_id 即可。请注意,firstWhere方法仅用于过滤加载的集合,因此它不会运行查询。 -
从性能的角度来看,xyz 的答案比 DigitalDrifter 的要快得多,与数据库引擎相比,使用 PHP 对大数据进行分组/求和/过滤太慢了。如果您甚至想改进 xyz 的答案,我会将
with('method')替换为selectRaw('SUM(amount) as total, methods.type')->join('methods', 'methods.id', '=' , 'expenses.method_id')->groupBy('method_id', 'methods.type'),这样您只需访问数据库一次,结果就已经很好地格式化了。