multicaret / laravel-acquaintances

This package gives Eloquent models the ability to manage friendships (with groups), followships along with Likes, favorites..etc.
https://laravel-news.com/manage-friendships-likes-and-more-with-the-acquaintances-laravel-package
MIT License
808 stars 72 forks source link

{{ $model->likers()->count() }} Eager ? #68

Closed f4xy closed 2 years ago

f4xy commented 3 years ago

Models/Thread.php ` class Thread extends Model { use HasFactory;

public function comments()
{
    return $this->morphMany(Comment::class, 'commentable')->whereNull('parent_id');
}

} `

Models/Comment.php ` class Comment extends Model { use HasFactory, CanBeLiked;

protected $with = ['user', 'replies'];

public function commentable()
{
    return $this->morphTo();
}

public function user()
{
    return $this->belongsTo(User::class);
}

//zi
public function replies()
{
    return $this->hasMany(Comment::class, 'parent_id')->oldest();
}

} `

Livewire/Comments.php `class Comments extends Component { public $model;

public function render()
{

    return view('livewire.comment.comments', [
        'comments' => $this->model
                            ->comments()
                            ->paginate(10)
    ]);
}

}`

Livewire/comment.php ` class Comment extends Component { public $comment;

public function render()
{
    return view('livewire.comment.comment', [
        'replys' => $this->comment->replies
    ]);
}

} `

When I call {{$model - > likers() - > count()}} on the front end, the N + 1 problem occurs.

I use ‘beyondcode/laravel-query-detector’ package to remind me:

截屏2021-09-01 下午10 52 46

and debugbar :

截屏2021-09-01 下午10 53 15

Thank you very much for providing such a powerful package, and I hope you can help me. This problem has bothered me for a week, but it still can't be solved. Thank you very much again!

mkwsra commented 3 years ago

You are always welcome,

For sure you can eager load the relations, simply, add the relation you want to, in your case (as far as I understand it) it must be 'likers'

So please add it to your with function or attribute of your model

Let me know if it worked or if you need any further help

f4xy commented 3 years ago

The problem is not solved.

I have added the preload function.

protected $with = ['user', 'replies', 'likers'] in Models/Comment;

Can you use withCount or morphWithCount in the package you develop?

The query data is too much, the reason why the EAGER function fails is that I used $model->likers()->count()

ronssij commented 2 years ago

{{ $model->likers()->count() }} this will always cause N + 1 because the ->likers() is a new query instance.

the prelaoded items will always work. but instead using the ->count() method you should use it like this count( $model-> likers).

but there is a cleaner way to do this.

eg.

return view('livewire.comment.comments', [
    'comments' => $this->model->comments()->withCount(['likers'])->paginate(10);
]);

-------------------------------------------------------------------------------------------
to explain:

$model = $this->model->comments()->withCount(['likers'])->paginate(10);

and so

// model should be looped in your case, this is to very the first item has the likers count
$item = $model[0];

$item->likers_count; // This is the eager loaded liker count.

and with replies() you can always add another methods on the relation.

return $this->hasMany(Comment::class, 'parent_id')->withCount(['likers'])->oldest();