- Don't use "select *", select the fields you need : "select users.name, ..."
- "profiles" table is really necessary? You could putt that in users if its only 4 fields.
- Add index
Optimize eloquent query
I'm facing a performance issue when fetching my user models.
My user model has a relation with many teams. The user has a separate profile for each team.
These are my db tables:
users
- id
- first_name
- last_name
profiles
- id
- role
- position
- nickname
- back_number
teams
- id
- name
team_user (pivot)
- team_id
- user_id
- profile_id
I'm looking for a better approach to query my users with desired profile for a specific team with the possibility to filter by profile role.
My models:
User.php
class User extends Model
{
public function teams()
{
return $this->belongsToMany(Team::class)->using(TeamUser::class)->withPivot('profile_id');
}
public function scopeFilter($query, $filters=null)
{
if (isset($filters['type'])) {
$query->where('profiles.type_id', $filters['type']);
} else {
$query->where('profiles.type_id', '!=', 3);
}
}
public function scopeOwners($query)
{
return $query->where('profiles.role', 2);
}
public function scopeWebmasters($query)
{
return $query->where('profiles.role', '>', 0);
}
public function scopeTeamProfile($query, $teamId)
{
return $query
->select('users.*')
->join('team_user', 'team_user.user_id', '=', 'users.id')
->join('profiles', 'profiles.id', '=', 'team_user.profile_id')
->where('team_user.team_id', $teamId)
->whereNull('profiles.deleted_at')
->orderBy('profiles.type_id')
->orderBy('users.last_name');
}
public function getProfileAttribute()
{
$teamId = 1;
$team = $this->teams->firstWhere('id', $teamId);
$profile = $team->pivot->profile;
return $profile;
}
}
TeamUser.php
class TeamUser extends Pivot
{
public function profile()
{
return $this->belongsTo('App\Profile');
}
}
Inside my controller
$team = 1;
$users = User::filter(['type' => $requestType])
->teamProfile($team)
->paginate(25);
But now the main issue. When access the profile data within the loop in blade:
{{ $user->profile->position }}
{{ $user->profile->nickname }}
{{ $user->profile->back_number }}
This results in a lot of extra unnecessary queries. I suppose the methods getProfileAttribute() and scopeTeamProfile() are the problem.
Any help would be great!
Regards, Bas
with('team.profile') ?
but I think you have a problem with your database as you merge 2 pivot tables.
Is the profile related to many teams, or many users ?
If I understand well : One user as many team, and for each team he has a specific profile. Thus, profile is related to one team.
- User many-to-many Team
- User One-to-many Profile
- Team One-to-many Profile
So you can :
- keep your
usersandteamstable. - delete the profile_id column in
team_user - add
user_idandteam_idin yourprofiletable - update your relationships
and go with : with('team.profile')
Please or to participate in this conversation.