I have an interface which displays a list of communities on the platform. Communities have members and in turn members/profiles can befriend one another. On the listing page each community card needs to display the number of members (in the community) and the number of friends (friends of logged in profile) from those members.
Here's an illustration of how a community card looks like
I'm getting the communities with the members first:
$communities = $loggedInProfile->communities->load('members')->take(15);
And then iterating over the communities and then the members to find out which ones are friends with the logged in user.
foreach ($communities as $key => $community) {
$friends = [];
foreach ($community->members as $member) {
if ($loggedInProfile->isFriendWith($member)) {
array_push($friends, $member);
}
}
$community->members_who_are_friends = $friends;
}
My issue is that this is very taxing in terms of the number of queries when the associations get large. Is there a better way of retrieving these relationships without having to use nested for loops? I'm also indexing all data with Elasticsearch. Would a retrieval of this sort be better with Elasticsearch? Also would this be a good use case for hasThrough
?
Update
The members
relationship:
public function members()
{
return $this->belongsToMany('App\Profile', 'community_members', 'community_id', 'profile_id')->withTimestamps();
}
The isFriendWith
relationship:
public function isFriendWith(Model $recipient)
{
return $this->findFriendship($recipient)->where('status', Status::ACCEPTED)->exists();
}
The check is done on a table called friendships
. The status
column (which can be either 0 or 1) is checked to see if friends or not.
The findFriendship
check:
private function findFriendship(Model $recipient)
{
return Friendship::betweenModels($this, $recipient);
}
Database structure:
-Profiles migration
Schema::create('profiles', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
-Communities migration (the foreign key is the owner
of the community)
Schema::create('communities', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('profile_id');
$table->foreign('profile_id')->references('id')->on('profiles');
$table->string('slug')->unique();
});
-Community_members migration
Schema::create('community_members', function (Blueprint $table) {
$table->primary(['profile_id', 'community_id']);
$table->unsignedInteger('profile_id');
$table->foreign('profile_id')->references('id')->on('profiles');
$table->unsignedInteger('community_id');
$table->foreign('community_id')->references('id')->on('communities');
$table->timestamps();
});
-Friendships migration
Schema::create('friendships'), function (Blueprint $table) {
$table->increments('id');
$table->morphs('sender');
$table->morphs('recipient');
$table->tinyInteger('status')->default(0);
$table->timestamps();
});