📜 ⬆️ ⬇️

Setting up Laravel relationships - counting comments (free translation)

I present to you a free translation of the article " Tweaking Eloquent Relations - how to get hasMany relation count efficiently? " From softonsofa.com.

When working with model relationships, you most likely would like to count the number of items received (for example, comments or likes). Obviously there are ways to do this, but not always effective, especially when you download a collection of models and their relationships.

Well, let me tell you what we can do about it.

hasMany relation
')
public function comments() { return $this->hasMany('Comment'); } 

The most straightforward way can be to use one of the two methods below (possibly wrapped in a getCommentsCount type method in the Post model):

 [1] > $post = Post::first(); // object(Post)( // 'incrementing' => true, // 'timestamps' => true, // 'exists' => true // ) [2] > $post->comments->count();// 4 [3] > $post->comments()->count();// 4 

However, this is still not the best solution.


When you need to get a collection of posts and count comments on them, then of course you can use join, groupBy and all that, but who cares? Why do we have to write something like this?

 $posts = Post::leftJoin('comments', 'comments.post_id', '=', 'posts.id') ->select('posts.*', 'count(*) as commentsCount') ->groupBy('posts.id') ->get(); 

If we prefer elegant syntax in the style of Eloquent.

 $posts = Post::with('commentsCount')->get(); 

That's what we need, let's finally do it. To force Eloquent to preload the number of our comments, we need to create a method in the model that returns a Relation object.

 public function comments() { return $this->hasMany('Comment'); } public function commentsCount() { return $this->comments() ->selectRaw('post_id, count(*) as aggregate') ->groupBy('post_id'); } 

It certainly works, but I would not be myself if I left everything as it is.

 $post = Post::with('commentsCount')->first(); $post->commentsCount; $post->commentsCount->first(); $post->commentsCount->first()->aggregate; 

Let's improve on the code a bit.


 public function commentsCount() { return $this->hasOne('Comment') ->selectRaw('post_id, count(*) as aggregate') ->groupBy('post_id'); } public function getCommentsCountAttribute() { if ( ! array_key_exists('commentsCount', $this->relations)) $this->load('commentsCount'); $related = $this->getRelation('commentsCount'); return ($related) ? (int) $related->aggregate : 0; } 

Now it is much easier and more beautiful to work with it.

 $post = Post::first(); $post->commentsCount; // 4 $posts = Post::with('commentsCount')->get(); $posts->first()->commentsCount; 

Source: https://habr.com/ru/post/302000/


All Articles