Как получить список сообщений и связанные теги с наименьшим количеством запросов

Мои таблицы структурированы следующим образом:

TAGS (больше категории): id, имя тега, описание, slug

POSTS: id, title, url …

POSTSTAGS: id, idPost, idTag

ПОЛЬЗОВАТЕЛИ: id, username, userSlug …

ГОЛОСОВ: id, idPost, idUser

У каждого сообщения может быть до пяти тегов, и каждый пользователь может голосовать только один раз. В настоящее время, поскольку теги еще не реализованы, я извлекаю свой разбитый на результат набор результатов со следующим запросом:

SELECT p.*, u.username, u.userSlug, u.id as userId, exists (select 1 from votes v where v.idUser=$id AND p.userId=v.idUser AND p.url = v.url) as voted FROM posts p JOIN users u ON u.id=p.userId ORDER BY p.created DESC LIMIT 10 OFFSET :offset 

Запрос запускается через PDO и возвращается в формате JSON в angularjs ng-repeat . Идентификатор $id является зарегистрированным идентификатором пользователя. Я использую его в exists подзапросе, чтобы серые кнопки голосования в моем угловом виде (есть также проверка на стороне сервера). Если кто-то щелкнет имя пользователя в представлении, он будет отправлен на страницу с подробной информацией, где будут показаны все сообщения пользователя ( userSlug для спасения).

Следующий шаг – включить теги в список результатов, и здесь я заикался. Каждое сообщение в списке должно содержать все связанные теги (tagName, description, slug), и каждый тег должен перейти на страницу сведений, где показаны все связанные записи для этого конкретного тега.

Первое решение, которое приходило на ум, заключалось в том, чтобы выполнить свой первый шаг после выполнения ранее упомянутого запроса:

 foreach ($postsResult as &$post) { $sql ="SELECT t.* FROM tags t JOIN poststags pt ON t.id=pt.idTag WHERE pt.idPost=$post->id"; $stmt=$db->prepare($sql); $stmt->execute(); $tagsResult=$stmt->fetchAll(PDO::FETCH_OBJ); $post->tags = $tagsResult; } $response->write(json_encode($postsResult)); 

Готово, легко peasy! Лоты запросов, которые будут создавать огромную нагрузку на сервер. И мы не хотим этого делать.

Второе решение состояло в том, чтобы запустить другой запрос, который извлекает все теги, связанные с postsResult (s), а затем вставляет соответствующие теги в каждое сообщение, позволяя PHP выполнять грязную работу.

 $sql = " SELECT t.*, pt.idPost FROM tags t JOIN poststags pt ON t.id=pt.idTag WHERE pt.idPost IN (array of post ids) "; $stmt=$db->prepare($sql); $stmt->execute(); $tagsResult = $stmt->fetchAll(PDO::FETCH_OBJ); foreach ($postsResult as &$post) { $arr = array(); foreach ($tagsResult as $tag) { if ($post->id==$tag->idPost) { $arr[]=$tag; } } $post->tags = $arr; } $response->write(json_encode($postsResult)); 

Есть ли лучший или более быстрый способ сделать это?