Optimize query Eloquent laravel for thousands records - laravel

I have a problem with a query in Laravel with many records, because it is so slow.
I have a table users that has 4934 records.
I have table of relations that for example is named user_relation_values that has 17482 records.
I have a table values that has 20495 records.
Now I receive,from front end, N id of users, so I could receive 1 id or 4934 ids or 2000 ids or 1000 ids, so I don't know how many ids I will receive.
I have to return, starting by ids received, the relations of model users with id.
So in My backend I have a function like this:
$users= $request->input('users');
$usersValues = array();
foreach ($users as $user){
$o = User::find($owner['id']);
$o->values;
$owersProperties[] = $o;
}
I have the relations in My User model:
public function values(){
return $this->belongsToMany('App\Models\Values');
}
I have put The various indexes on tables but the query Is so slow if I receive the all id.
If I receive all 4934 ids the query takes more than 20 seconds, but I read that someone make query for milions of records in just over 5 seconds.
How can I optimize my table or my query?

Looking at your example code, you’re query users in a loop (n queries), and then also querying values for each user. That’s going to issue an exponential number of queries. Instead, you should query the users and eager-load the values relationship.
If you’re getting an array of user IDs as input, then you can pass that to Eloquent’s find() method:
$users = User::find($request->input('users'));
You should also eager-load the values relationship if you plan on using it in a loop:
$users = User::with('values')->find($request->input('users'));
This should dramatically reduce the number of queries you issue.

Related

laravel query does not return the entire count of the rows of the relationship

i have a query that i want to return an object with its relationship, it has a many to one relationship, one order can have more than one drug i wrote a query like this
$orders = DrugRequest::where('user_id', $user_id)->with(['drugs'])->latest()->get();
this gets the relationship but not the full rows, for example if an order has two drugs it only returns the first drug not both,
this is my relationship
public function drugs(){ return $this->hasMany('App\OrderDrug' , 'order_id' , 'id');}
and this is when i dd($orders)
for the order object with the index 11 i have two drugs but it only returns one drug
i found the issue it was the query, i made the changes and it worked like this:
$orders = DrugRequest::where('user_id', $user_id)->with('drugs')->latest()->get();

Using Laravel Eloquent to count how many times something exists in an efficient manner

I have a table called rentals, within each row are columns state,city,zipcode which all house ids to another table with that info. There are about 3400 rentals. I am pulling each column to display the states,city and zipcode distinctly. I need to show how many rentals are in each one. I am doing this now via ajax, the person starts typing in what they want to see and it auto completes it with the count, but its slow because of the way im doing it.
$rentals_count = Rentals::where('published',1)->get();
foreach($states as $state) {
echo $state.”-“.$rentals_count->where(‘state’,$state->id)->count();
}
Above is roughly what im doing with pieces removed because they are not related to this question. Is there a better way to do this? It lags a bit so the auto complete seems broken to a new user.
Have you considered Eager loading your eloquent query? Eager loading is used to reduce query operations. When querying, you may specify which relationships should be eager loaded using the with method:
$rental_counts = Rentals::where('published',1)->with('your_relation')->get();
You can read more about that in Laravel Documentation
$rentals = Rentals::wherePublished(true)->withCount('state')->get();
When you loop through $rentals, the result will be in $rental->state_count
Setup a relation 'state' on rentals then call it like this
$rentals_count = Rentals::where('published',1)->with('state')->get()->groupBy('state');
$rentals_count->map(function($v, $k){
echo $v[0]->state->name .' - '. $v->count();
});
Meanwhile in Rentals Model
public function state(){
return $this->hasOne(State::class, 'state'); //state being your foreign key on rentals table. The primary key has to be id on your states table
}

show rows with a relation before in Laravel

in a Laravel application, I have a list of companies. Some of those are related to a subscriptions table in a 1 x n relation.
I want to order the companies in a way that the ones which have a subscription appear before the ones which have no subscription using just one db query.
Any idea is much appreciated!
thanks!
Laravel uses separate queries to eager load relationships. So if you want to do this you will need to join the tables and order by...
Something in the form...
$companies = App\Companies::join('subscriptions as sub', 'sub.company_id', '=', 'company.id')
->orderBy('sub.somefield', 'DESC')
->select(what you need)
->with('if you need the relation data');
You know you can also only query those records that have a relationship with
$companies = App\Companies::has('subscription')->get();
Maybe that is all you need... and
$companies = App\Companies::doesntHave('subscription')->get();
... returns the opposite where the company has no subscription...

Provide extra condition in eager loading which includes comparing of two columns, laravel

I have tables students, profiles, subjects and pivot table profile_subject
-students---------{id,profile_id,year}
-profiles---------{id}
-profile_subject--{profile_id,subject_id,year}
-subjects---------{id}
I want to select a student with id 5, and eager load profile and subjects for the students year.
Something like this:
$student = Student::with('profile','profile.subjects')->find(5);
But I also have to insert the condition
->wherePivot('year','=','students.year')
there somewhere. How to do that?
This query will not do the job cos it will search for records which year is "students.year" literary
Use lazy eager loading. This code will not create any additional queries, it'll create the same amount of queries as with() would:
$student = Student::find(5);
$sudent->load(['profile', 'profile.subjects' => function ($q) use ($student) {
$q->wherePivot('year', $student->year);
}]);

Laravel eloquent - get the count of rows of the pivot table in many to many relationship

I need to get the count of all the rows in the pivot user_engagement. I have defined a many to many relationship for users and engagements. I am getting the number with a raw query at the moment, but would like to change this query in to an eloquent one if possible:
$numberOfEngagements = DB::table('user_engagement')->count();
Create model for your many to many relationship table and try this
$count = App\UserEngagement::all()->count();
Faster and memory friendly:
$count = App\UserEngagement::count();

Resources