I’ve built a nested comment system and it works fine, but I have a problem. when I want to show the comments, it runs too many queries. for example if I have 10 comments and two replies each, laravel debugger shows 40+ queries, and I want to reduce them, here is my code :
Query
$comments = $post->mentions()->with(['author', 'reply'])->get();
Relationship in Post.php Model
public function mentions() { return $this->hasMany(Comment::class, 'post_id')->where('approved',1)->where('parent_id',0); }
Comments Relationships
public function author() { return $this->belongsTo(User::class, 'author_id')->select('id', 'name', 'avatar', 'role'); } public function reply() { return $this->hasMany(Comment::class, 'parent_id')->where('approved', 1); }
Blade File
@foreach ($comments as $comment) <div x-data="{reply:false}" class="break-words bg-white border-2 rounded-lg p-4 my-5" id="answer-{1}"> <div wire:ignore class="flex justify-between items-center"> <div class="flex items-center"> <img class="rounded-full w-20 border-4 @if ($comment->author->role == 'administrator') border-blue-500 @else border-gray-500 @endif " src="{{ $comment->author->avatar }}" alt="{{ $comment->author->name }}"> <div> <div class="flex pr-3"> <a href="/@username" class="font-bold text-lg text-gray-800 hover:text-gray-900">{{ $comment->author->name }}</a> @if ($comment->author->role == 'administrator') <img class="w-5 mr-1" src="/img/verified.svg" alt="" title="admin"> @endif </div> <p class="font-light cursor-default text-gray-700 pt-1 pr-3"> {{ $comment->created_at->diffForHumans() }}</p> </div> </div> <svg @click="reply = true" xmlns="http://www.w3.org/2000/svg" class="h-6 cursor-pointer hover:text-rose-600" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" /> </svg> </div> <div class="comment_body leading-8 pt-3 text-gray-800 cursor-default"> <div wire:ignore> {!! nl2br($comment->body) !!} </div> <div x-cloak x-show="reply"> <form class="py-3" wire:submit.prevent="SubmitComment({{ $comment->id }})"> <textarea wire:model.defer="commentBody" class="w-full focus:ring-0 bg-zinc-200 border shadow focus:bg-zinc-100 mt-3 p-4 rounded-lg" id="editor" rows="6" placeholder=""></textarea> @error('commentBody') <p class="text-red-600 mt-1 text-sm">{{ $message }}</p> @enderror <div class="flex mt-3"> <div @click="reply = false" class="bg-red-600 rounded-lg ml-3 text-white px-3 py-2 cursor-pointer"> Cancel </div> <button wire:loading.remove wire:target="SubmitComment" type="submit" class="inline-block bg-gray-800 hover:bg-gray-900 transition duration-300 px-3 py-2 text-white rounded-md"> Send </button> <button wire:loading="" wire:target="SubmitComment" type="button" class="flex bg-gray-800 hover:bg-gray-900 transition duration-300 px-3 py-2 text-white rounded-md" disabled> <span class="flex justify-center"> <svg class="animate-spin w-6 h-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"> </path> </svg> </span> </button> </div> </form> </div> <div class="my-3"> @include('partials.comment',['comments'=>$comment->reply]) </div> </div> </div> @endforeach
Advertisement
Answer
You can use dot seperator to get the nested relationship
$comments = $post->with(['mentions.author','mentions.reply']) ->first() ->mentions;