in my application I have a long list of Categories. I load them with this:
$categories = Categories::all();
In the Categories
there is this function:
public function transactions()
{
return $this->hasMany(Transactions::class);
}
public function getPreviousActivityAttribute() {
return $this->transactions()
->where('date', '<' Carbon::now()->firstOfMonth())
->sum('amount');
}
I render this list of Categories as a table. Each row is calling $category->previousActivity
.
This results in n+1 database queries, where n is the number of Categories (and its a lot). Apart from previousActiviy
I display other Aggregates aswell (some do SUM
others do AVG
, etc.).
By the way. There are a lot of transactions. I cannot load them all using Categories::with('transactions')->get()
. This would require too much memory.
Is there a way to eager load aggregates? There is a withCount
method on the query builder, but it does not really help here.
Thank you for your help.
A clean solution would be to use withCount
as follows:
In Categories.php:
public function withPreviousActivity()
{
return $this->withCount([
'transactions as previous_activity' => function ($query) {
$query->select(DB::raw("SUM(IFNULL(amount,0)) as transactions_count"))->where('date', '<', Carbon::now()->firstOfMonth());
},
]);
}
Somewhere else:
dump(Categories::withPreviousActivity()->get()->toArray());
Attach a function to the withCount
attribute in the model˚s constructor like this to always eager load this count.
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->withCount['transactions as total'] = function ($query) {
$query->select(DB::raw(
'SUM(IFNULL(amount, 0)) as relationsum'
));
};
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.