Оптимизация поиска красноречивых отношений - PullRequest
1 голос
/ 03 апреля 2019

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

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

enter image description here

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

$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('App\Profile', '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 Ответ

0 голосов
/ 03 апреля 2019

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

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

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

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