Laravel для многих моделей, связанных с загрузкой, с подсчетом

Я пытаюсь связать 4 таблицы, а также добавить настраиваемое поле, рассчитанное путем подсчета идентификаторов некоторых связанных таблиц с использованием laravel. У меня есть это в SQL, который делает то, что я хочу, но я думаю, что это можно сделать более эффективным:

DB::select('SELECT posts.*, users.id AS users_id, users.email,users.username, GROUP_CONCAT(tags.tag ORDER BY posts_tags.id) AS tags, COUNT(DISTINCT comments.id) AS NumComments, COUNT(DISTINCT vote.id) AS NumVotes FROM posts LEFT JOIN comments ON comments.posts_id = posts.id LEFT JOIN users ON users.id = posts.author_id LEFT JOIN vote ON vote.posts_id = posts.id LEFT JOIN posts_tags ON posts_tags.posts_id = posts.id LEFT JOIN tags ON tags.id = posts_tags.tags_id GROUP BY posts.id, posts.post_title'); 

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

 $trending=Posts::with(array('comments' => function($query) { $query->select(DB::raw('COUNT(DISTINCT comments.id) AS NumComments')); },'user','vote','tags'))->get(); 

Однако значение NumComments не отображается в результатах запроса. Есть ли какие-нибудь подсказки, как еще об этом поступить?

Вы не можете использовать это with помощью, потому что он выполняет отдельный запрос.

Вам нужно простое join . Просто переведите запрос, который у вас есть, например:

 Posts::join('comments as c', 'posts.id', '=', 'c.id') ->selectRaw('posts.*, count(distinct c.id) as numComments') ->groupBy('posts.id', 'posts.post_title') ->with('user', 'vote', 'tags') ->get(); 

то каждый пост в коллекции будет иметь атрибут count:

 $post->numComments; 

Однако вы можете упростить такие отношения, как ниже:

Хотя первое решение лучше с точки зрения производительности (может быть, не заметно, если у вас нет больших данных)

 // helper relation public function commentsCount() { return $this->hasOne('Comment')->selectRaw('posts_id, count(*) as aggregate')->groupBy('posts_id'); } // accessor for convenience public function getCommentsCountAttribute() { // if relation not loaded already, let's load it now if ( ! array_key_exists('commentsCount', $this->relations)) $this->load('commentsCount'); return $this->getRelation('commentsCount')->aggregate; } 

Это позволит вам сделать это:

 $posts = Posts::with('commentsCount', 'tags', ....)->get(); // then each post: $post->commentsCount; 

И для многих-многих отношений:

 public function tagsCount() { return $this->belongsToMany('Tag')->selectRaw('count(tags.id) as aggregate')->groupBy('pivot_posts_id'); } public function getTagsCountAttribute() { if ( ! array_key_exists('tagsCount', $this->relations)) $this->load('tagsCount'); $related = $this->getRelation('tagsCount')->first(); return ($related) ? $related->aggregate : 0; } 

Другие примеры, подобные этому, можно найти здесь http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/