I have two models, Plan
and Transactions
. Each Plan
can have many Transactions
. I want to get the total amount of all transactions related to all plans. Right now I am doing it like this:
$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.
But I want to get rid of the foreach loops and use filter
and/or map
instead. I have tried the following:
$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
});
I'm sorta getting stuck in this last bit, where I end up with a collection of collections. Any ideas of how to accomplish this, at least without using the foreach loops? Perhaps maybe in the query itself?
So what I have is a few Plans
, and each Plan
can have many Transactions
. Each Transaction
has an amount
field, in which I store the amount for each Transaction
. I want to get the TOTAL AMOUNT for ALL transactions which are related to a Plan. So, the sum of the transactions.amount.
Assuming you already have a plan, the transactions property on that plan will be a collection, so you can use the sum()
method on that:
$total = $plan->transactions->sum('amount');
Since it's just one specific plan, it doesn't matter whether you eager load it or not. But if it hasn't been loaded already, you can just do it through the database instead:
$total = $plan->transactions()->sum('amount');
If you have a collection of plans, use reduce()
:
$total = $plans->reduce(function ($carry, $plan) {
return $carry + $plan->transactions->sum('amount');
}, 0);
In this case, you do want to eager load the transactions to reduce the number of queries. (Otherwise, please refer to the above on going through the database instead.)
If you're coming from a query, you can either use joins or double queries - the latter is generally simpler:
$ids = Plan::where('condition')->pluck('id')->all();
$total = Transaction::whereIn('plan_id', $ids)->sum('amount');
And, of course, if you just want the total amount no matter what, there's no need to go through the plans at all. :)
$total = Transaction::sum('amount');