Оптимизация поиска отношений Eloquent

#mysql #laravel #eloquent #relationship

#mysql #laravel #eloquent #отношения

Вопрос:

У меня есть интерфейс, который отображает список сообществ на платформе. В сообществах есть участники, и, в свою очередь, участники / профили могут дружить друг с другом. На странице со списком каждой карточки сообщества должно отображаться количество участников (в сообществе) и количество друзей (друзья, зарегистрированные в профиле) из этих участников.

Вот иллюстрация того, как выглядит карточка сообщества

введите описание изображения здесь

Сначала я получаю сообщества с участниками:

 $communities = $loggedInProfile->communities->load('members')->take(15);
  

А затем перебор сообществ, а затем участников, чтобы выяснить, какие из них являются друзьями зарегистрированного пользователя.

    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;
    }
  

Моя проблема в том, что это очень обременительно с точки зрения количества запросов, когда ассоциации становятся большими. Есть ли лучший способ получения этих отношений без использования вложенных циклов for? Я также индексирую все данные с помощью Elasticsearch. Будет ли поиск такого рода лучше с помощью Elasticsearch? Также было бы это хорошим вариантом использования для hasThrough ?

Обновить

members Отношения:

 public function members()
{
    return $this->belongsToMany('AppProfile', 'community_members', 'community_id', 'profile_id')->withTimestamps();
}
  

isFriendWith Отношения:

 public function isFriendWith(Model $recipient)
{
    return $this->findFriendship($recipient)->where('status', Status::ACCEPTED)->exists();
}
  

Проверка выполняется в таблице с именем friendships . status Столбец (который может быть либо 0, либо 1) проверяется, чтобы увидеть, есть ли друзья или нет.

findFriendship Проверка:

 private function findFriendship(Model $recipient)
{
    return Friendship::betweenModels($this, $recipient);
}
  

Структура базы данных:

-Миграция профилей

 Schema::create('profiles', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users');
});
  

-Миграция сообществ (внешний ключ является owner сообщества)

 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

 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();
});
  

-Миграция дружеских отношений

 Schema::create('friendships'), function (Blueprint $table) {
    $table->increments('id');
    $table->morphs('sender');
    $table->morphs('recipient');
    $table->tinyInteger('status')->default(0);
    $table->timestamps();
});
  

Комментарии:

1. можете ли вы показать мне функцию getMutualFriends ? какое поле $member вы там используете?

2. Извините за это, я использовал неправильную проверку на дружбу. Обновил вопрос. Участник — это член сообщества, которое я просматриваю. Я перебираю отношения members () в сообществе.

3. покажите мне function isFriendWith($member) или просто скажите мне, какое поле $ member вы используете, чтобы узнать, взаимно ли это

4. Обновленный вопрос.

5. участник — это экземпляр пользователя, верно? то же, что и loggedUser ..

Ответ №1:

В вашей строке:

 $communities = $loggedInProfile->communities->load('members')->take(15);
  

load() используется для выполнения отложенной загрузки, т. Е. вы загружаете участников после извлечения сообществ, что приводит к различным запросам для каждого сообщества. Вы могли бы извлечь все данные с помощью одного запроса с помощью with() . Кроме того, take(15) выполняется для результирующей коллекции, а не для запроса. Попробуйте это:

 $communities = $loggedInProfile->communities()->with('members')->take(15)->get();
  

Комментарии:

1. Я попробовал оба подхода, и, похоже, это не влияет на количество выполняемых запросов :/.