Laravel减少关系查询

时间:2018-06-29 21:46:07

标签: laravel relation

我有两个模型。 ExpenseMethod。我想为每个sum抓住所有expenses中的method type。我有四种类型:

- 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 ▶}
  ]
}

我基本上需要这样简单的东西:

“银行” =>“这里所有使用'银行'方法的费用的总和” “ credit-card” =>“这里所有使用'credit-card'方法的费用的总和”

以此类推。

我认为->groupBy('type')->each->sum('amount')可以解决问题,但不能完全解决。如上面的集合示例所示,它会按类型分组,但不会给出每种类型的总和。

2 个答案:

答案 0 :(得分:2)

您可以按方法ID分组,然后将结果加到一条select语句中。

以下未经测试。

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

答案 1 :(得分:1)

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

$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');