Noob Coder
Noob Coder

Reputation: 2896

Laravel Eloquent: Reduce number of queries

Let's say I have 250 users in users table and each user has one or many books, and each book has one or many chapters. Now I would like to print the user names, with their book names.

Controller:

$users = User::all();

in blade:

@foreach($users as $user)
  <tr>
      <td>{{ $user->id }}</td>
      <td>{{ $user->name }}</td>
      <td>
        @foreach($user->books as $book)
          {{ $book->name }},
          @endforeach
      </td>
  </tr>
@endforeach

# of queries 252

Now to overcome the n+1 problem, the query should be

$users = User::with('books')->get();

Now the # of queries are only 2.

I want to print the book names with number of chapters like this-> BookName(# of chapters). So in my blade

@foreach($users as $user)
      <tr>
          <td>{{ $user->id }}</td>
          <td>{{ $user->name }}</td>
          <td>
            @foreach($user->books as $book)
              {{ $book->name }} ({{ $book->chapters->count() }}),
              @endforeach
          </td>
      </tr>
    @endforeach

so for 750 books with 1500 chapters the # of queries are about 752 and it increases if chapter number increases.

Is there any better Eloquent way to reduce it or should I go for raw SQL queries?

Upvotes: 1

Views: 4973

Answers (2)

Alexey Mezenin
Alexey Mezenin

Reputation: 163788

You don't need to load all chapters data and then manually count each collection. Use withCount() instead:

$users = User::with('books')->withCount('chapters')->get();

If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.

Upvotes: 10

maiorano84
maiorano84

Reputation: 11951

From the Eloquent Documentation:

Nested Eager Loading

To eager load nested 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 in one Eloquent statement:

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

In your case, you can retrieve the nested relationships you need with the following:

User::with('books.chapters')->get();

Upvotes: 6

Related Questions