How to Use Eager Loading in foreach Loop Laravel

How to Use Eager Loading in foreach Loop Laravel
Gregory Shein
How to Use Eager Loading in foreach Loop Laravel

This is a short and hopefully simple article for beginners to clarify a bit about how eager loading works in laravel and what are some differences between $post->comments and $post->comments() because the difference can be quite massive.

First, the basics: $post->comments returns a collection and $post->comments() returns a relation. But what does that mean? Collection is a collection of actual records from the database, as you might’ve thought. Relation is a draft of a database request, which isn’t actually executed. it can look something like this

>>> $city->districts()
=> Illuminate\Database\Eloquent\Relations\HasMany {#4444}
>>> $city->districts
=> Illuminate\Database\Eloquent\Collection {#4466
     all: [{id:1, name: 'Dubai Marina'}, {id: 2, name: 'Business Bay'}],
   }

Since it’s draft which hasn’t been executed, you can extend it however you like:

>>> $withDescription = $city->districts()->whereNotNull('description')
=> Illuminate\Database\Eloquent\Relations\HasMany
>>> $withoutDescription = $city->districts()->whereNull('description')
=> Illuminate\Database\Eloquent\Relations\HasMany

So if you didn’t execute the query, you can call a handy toSql() method on it, to see what is actually going on behind Eloquent engine:

>>> $city->districts()->toSql()
=> "select * from `districts` where `districts`.`city_id` = ? and `districts`.`city_id` is not null"

>>> $withoutDescription->toSql()
=> "select * from `districts` where `districts`.`city_id` = ? and `districts`.`city_id` is not null and `description` is null"
>>> $withDescription->toSql()
=> "select * from `districts` where `districts`.`city_id` = ? and `districts`.`city_id` is not null and `description` is not null"

With the theory out of the way, let’s see how it works in real life. So you have a post page, and you pass data from the controller to a blade view like this:

public function show($id)
{
    $post = Post::findOrFail($id);
    return view('post', compact('post'));
}

And in the view you have for example:

@foreach ($post->comments as $comment) 
Author {{ $comment->author->name }}
Text {{ $comment->text }}
@endforeach

Two quick notes: if you do @foreach($post->comments() as $comment) it won’t work, because the relation is not iterable.  $post->comments()->get() on the other hand will, because it’s essentially $post->comments

Second: this code will do lazy loading by default i.e., Laravel won’t load info from the database until it understands it needs that. Namely in the controller, it will load 1 record (post) and in the blade, it’ll first load comments to the post, then it’ll load Author for each comment (in our example it’s in a separate table).

Usually, I think code performance optimization gets much more attention than needed, but when it comes to database queries you can have literally hundreds of database queries for each page and your site will collapse working even on a small database and a small number of users (our team record was dev site would stop working when 3 people would browse it simultaneously). Those moments are always embarrassing especially because the issue is extremely easy to solve. Just use Eager Loading using with(). In our case:

Post::with(['comments', 'comments.author'])->findOrFail(1)
// or
$post = Post::findOrFail(1)
if ($someCondition) {
     $post->load(['comments', 'comments.author'])
}

There are also cool things like constraining eager loading

$users = App\Post::with(['comments' => function ($query) {
    $query->where('status', 'approved');
}])->get();

The above gets only approved comments. But to be honest, except for rather rare exceptions like the above, when we really do display only approved comments, tinkering too much with eager loading is a bad idea. It can lead to rather obscure and unexplainable bugs (like you will most likely forget about constraints in the controller because your muscle memory tells you that $post->comments should loop through ALL comments, not only approved ones). And 95% of the result you’ll get by just using eager loading in the most basic way anyways.

I’d leave stuff like lazy eager loading and constrained eager loading for the times when you’ll be sure you really need it.

Most importantly: all that is described pretty well in the docs on eager loading but by the popularity of this query in Google I understand that people don’t read docs much.

Ecommerce info block
Contact us to learn more

Hire a eCommerce Web or App Developer

Custom eCommerce development starts with your needs. No matter what size your business is, crafting killer websites or robust applications with Nomadic Soft is a winning strategy. Our development team will always use the latest tech tools to build your business interactive and engaging web interfaces and applications.

Contact Us

By sending this form I confirm that I have read and accept Nomadic soft Privacy Policy
×
Thanks!
Sent!
×
Error!