Laravel 减少关系查询

Laravel reducing relationship queries

我有两个模型。 ExpenseMethod。我想为每个 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" => "total sum here for all expenses that have a method of 'bank'" "credit-card" => "total sum here for all expenses that have a method of 'credit-card'"

等等..

我认为这一点 ->groupBy('type')->each->sum('amount') 可以解决问题,但不完全。它确实按类型分组,但没有给出每种类型的总和,如您在上面的集合示例中所见。

您可以按方法 ID 分组,然后在 select 语句中对结果求和。

以下未测试。

$expenses = auth()->user()
                  ->expenses()
                  ->select(DB::raw('SUM(amount) as total'), 'other_select_fields', ...)
                  ->with('method')
                  ->groupBy('method_id')
                  ->get();

您可以使用可用的收集方法执行此操作:

$expenses = auth()->user()->expenses()->with('method')->get();

$groupedSums = $expenses->map(function ($expense) {
    return [
        'type' => $expense['method']['type'],
        'amount' => $expense['method']['amount']
    ];
})->groupBy('type')->each->sum('amount');