【问题标题】:Laravel reducing relationship queriesLaravel 减少关系查询
【发布时间】:2023-03-06 09:45:01
【问题描述】:

我有两个模型。 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" => "此处为所有具有 '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'),这样您只需访问数据库一次,结果就已经很好地格式化了。

标签: laravel relation


【解决方案1】:

您可以按方法 id 分组,然后在 select 语句中汇总结果。

以下内容未经测试。

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

【讨论】:

    【解决方案2】:

    您可以使用可用的收集方法来做到这一点:

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

    【讨论】:

    • 删除了我的评论并编辑了我的答案,也许你可以检查我的编辑并帮助修复最后一点:)
    猜你喜欢
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 1970-01-01
    • 2023-02-02
    • 2023-02-17
    • 2015-06-04
    • 1970-01-01
    相关资源
    最近更新 更多