I have this code in Laravel 5, using Eloquent, which is working perfectly:
$filterTask = function($query) use ($id) { $query->where('taskid', $id); }; User::whereHas('submissions', $filterTask)->with(['submissions' => $filterTask])->get();
Basically the goal is to get only those users with their filtered submissions, which has any of them. However, it seems wasting to run both whereHas and with methods with the same callback function. Is there a way to simplify it?
Thanks.
with() function is used to eager load in Laravel. Unless of using 2 or more separate queries to fetch data from the database , we can use it with() method after the first command. It provides a better user experience as we do not have to wait for a longer period of time in fetching data from the database.
A one-to-one polymorphic relationship is a situation where one model can belong to more than one type of model but on only one association. A typical example of this is featured images on a post and an avatar for a user. The only thing that changes however is how we get the associated model by using morphOne instead.
Eager loading is super simple using Laravel and basically prevents you from encountering the N+1 problem with your data. This problem is caused by making N+1 queries to the database, where N is the number of items being fetched from the database.
In terms of performance you can't really optimize anything here (except if you were to move from eloquent relations to joins). With or without whereHas
, two queries will be run. One to select all users another one to load the related models. When you add the whereHas
condition a subquery is added, but it's still two queries.
However, syntactically you could optimize this a bit by adding a query scope to your model (or even a base model if you want to use this more often):
public function scopeWithAndWhereHas($query, $relation, $constraint){ return $query->whereHas($relation, $constraint) ->with([$relation => $constraint]); }
Usage:
User::withAndWhereHas('submissions', function($query) use ($id){ $query->where('taskid', $id); })->get();
The 'macroable' way (Laravel 5.4+)
Add this inside a service provider's boot()
method.
\Illuminate\Database\Eloquent\Builder\Eloquent::macro('withAndWhereHas', function($relation, $constraint){ return $this->whereHas($relation, $constraint)->with([$relation => $constraint]); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With