A
A
Alexey Sklyarov2021-04-13 12:15:35
Laravel
Alexey Sklyarov, 2021-04-13 12:15:35

How to solve N+1 DB query issue when fetching model with getNameAttribute?

There is a feedback system for posts that works like this: You can leave a review for a post, and a comment for a review. It turns out 3 models Post, Review, Comment. In the Post model, I create a new attribute that returns the number of comments on a post via the comments of that post.

public function getCommentsCountAttribute() : int
    {
        return $this->hasManyThrough(
                Review::class,
                Comment::class,
                'commentable_id',
                'reviewable_id'
            )
            ->where('commentable_type', Review::class)
            ->count();
    }


But since this is a post attribute (comments_count), it is calculated for each post, it turns out that in addition to selecting 30 posts, I make one request for each post to count the number of comments, it turns out that I additionally make 30 requests.

Is there an option to add an attribute selection as well as a relation through Post::with()or is it necessary to load all reviews in advance in posts, with preloaded comments, and then work with already loaded data in the method? Or is there a better way?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexey Ukolov, 2021-04-13
@0example

This is what should work:

public function reviews(): HasManyThrough
{
    return $this->hasManyThrough(
        Review::class,
        Comment::class,
        'commentable_id',
        'reviewable_id'
    );
}

public function getCommentsCountAttribute(): int
{
    return $this
        ->reviews
        ->where('commentable_type', Review::class)
        ->count();
}

Well, yes, when fetching, you must specify that you want to eagerly load comments for the collection of posts.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question