⬡ Lacelium
⌘K
Version 2.x ▾

Eager Loading

Introduction

When accessing Eloquent relationships as properties, the related models are "lazy loaded". This means the relationship data is not actually loaded from the database until you first access the property. However, lazy loading can lead to the infamous "N + 1" query problem.

The N + 1 Query Problem

To illustrate the N + 1 query problem, consider a Book model that is related to an Author model:

// Lazy Loading (BAD: N + 1 Queries)
$books = Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}

This loop will execute 1 query to retrieve all of the books from the database table, then another query for each book to retrieve the book's author. So, if you have 100 books, this code would run 101 database queries!

Eager Loading with with()

Thankfully, we can use eager loading to reduce this operation to just 2 queries. When building a query, you may specify which relationships should be eager loaded using the with method:

// Eager Loading (GOOD: Exactly 2 Queries)
$books = Book::with('author')->get();

foreach ($books as $book) {
    echo $book->author->name;
}

For this operation, only two queries will be executed:

select * from books;
select * from authors where id in (1, 2, 3, 4, 5, ...);

Eager Loading Multiple Relationships

Sometimes you may need to eager load several different relationships in a single operation. To do so, simply pass an array of relationships to the with method:

$books = Book::with(['author', 'publisher', 'comments'])->get();

Nested Eager Loading

To eager load a relationship's relationships, you may use "dot" syntax. For example, let's eager load all of the book's authors and all of the author's personal contacts:

$books = Book::with('author.contacts')->get();

Constraining Eager Loads

Sometimes you may wish to eager load a relationship, but also specify additional query conditions for the eager loading query. You can accomplish this by passing an array of relationships where the array key is the relationship name and the array value is a closure that adds constraints to the eager load query:

$users = User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%Lacelium%');
}])->get();

Lazy Eager Loading

Sometimes you may need to eager load a relationship after the parent model has already been retrieved. For example, this may be useful if you need to dynamically decide whether to load related models:

$books = Book::all();

if ($someCondition) {
    $books->load('author', 'publisher');
}

If you would like to load a relationship only if it has not already been loaded, use the loadMissing method:

$books->loadMissing('author');

Next Steps