Laravel使用过滤器和地图而不是foreach

时间:2017-07-16 09:05:32

标签: php laravel dictionary foreach filter

我有两个模型,PlanTransactions。每个Plan都可以有多个Transactions。我想获得与所有计划相关的所有交易的总金额。现在我这样做:

    $plans = $this->plan->with('transactions')->get();

    $total = [];

    foreach($plans as $plan)
    {
        foreach($plan->transactions as $transaction)
        {
            $total[] = $transaction->amount;
        }
    }

    dd(array_sum($total)); // Works, I get the total amount of all transactions that are related to a Plan.

但我想摆脱foreach循环并改用filter和/或map。我尝试过以下方法:

    $test = $plans->filter(function ($plan) {
        return $plan->has('transactions');
    })->map(function ($plan) {
        return $plan->transactions;
    })->map(function ($transaction) {
        return $transaction; // Not sure what to do here, $transaction->amount doesn't work
    });

我有点陷入最后一点,我最终得到了一系列收藏品。关于如何实现这一点的任何想法,至少不使用foreach循环?也许在查询本身?

所以我拥有的是Plans,而Plan每个Transactions都有Transaction。每个amount都有一个Transaction字段,我在其中存储每个{{1}}的金额。我希望获得与计划相关的所有交易的总金额。所以,transactions.amount的总和。

2 个答案:

答案 0 :(得分:1)

由于您有计划ID,因此可以使用sum()方法:

$this->transaction->where('plan_id', $planId)->sum('amount');

要计算所有交易的金额,请移除where()部分。

要计算多个计划的金额,请使用whereIn() intsead where()

答案 1 :(得分:1)

假设您已有计划,该计划上的交易属性将是一个集合,因此您可以使用sum()方法:

$total = $plan->transactions->sum('amount');

因为它只是一个特定的计划,所以你是否急于加载并不重要。但是如果它还没有加载,你可以通过数据库来代替它:

$total = $plan->transactions()->sum('amount');

如果您有一系列计划,请使用reduce()

$total = $plans->reduce(function ($carry, $plan) {
    return $carry + $plan->transactions->sum('amount');
}, 0);

在这种情况下,您确实希望加载事务以减少查询次数。 (否则,请通过数据库参考上面的内容。)

如果您来自查询,可以使用联接或双查询 - 后者通常更简单:

$ids = Plan::where('condition')->pluck('id')->all();
$total = Transaction::whereIn('plan_id', $ids)->sum('amount');

当然,如果您只想要总量,那么根本不需要完成计划。 :)

$total = Transaction::sum('amount');