Is there a better way to optimise 2 loops running, one inside another. I have a list of categories and each category has bunch of topics. I'm pulling all categories belonging to given parent element (subject) and all topics that have relationship to a category.
Inside my view I'm running a loop of categories and inside it I have another foreach loop with if statement checking if topic belongs to given category - if yes - show its details.
I had a look at the queries in debugbar and I can see one query for all topics, then inside a loop another 'topic' query for each category id, 15 queries in total just for topics.
Is there a better way to structure it so I don't have so many queries?
Yes, eager-load the topics associated with the category(ies), you can do this all in a single Eloquent statement assuming the appropriate relationships are present and correct:
Now, the Subject instance will have a categories property which is a Collection of Category instances; and further, each Category instance will have a topics property which is a Collection of the associated Topic instances. This will result in exactly 3 queries, one for Subject one for all of the Categories, and one for all of the Topics - Laravel will put together the Category instances with their associated Topics.
In your view:
@foreach($subject->categories as $category)
{{ $category->name }}
@foreach($category->topics as $topic)
{{ $topic->name }}
@endforeach
@endforeach
Do you mean every topic - not just the topics associated with the current Category? You could make one extra query for all Topics:
$topics = Topic::all();
Then what; you want to display every topic under each displayed Category, and highlight the associated ones? You can check the current Category's topics Collection includes the current topic (from the all topics Collection):
@foreach ($categories as $category)
@foreach ($topics as $topic)
{{ $topic->name}}
@if ($category->topics->includes($topic))
// display a check mark or whatever
@endif
@endforeach
@endforeach
I mean to show the appropriate ones - with eager load I'm grabing subject with categories and topics.
But in my view do I still have collections $categories and $topics even though I'm not using it in my controller?
then everything you need is inside the $subject object, i.e. $subject->categories, and each $category has $category->topics - like I described earlier.