Home Arrow Icon Knowledge base Arrow Icon Global Arrow Icon Can you provide examples of inefficient query designs that can be fixed with whenLoaded()


Can you provide examples of inefficient query designs that can be fixed with whenLoaded()


Examples of inefficient query designs that can be fixed using Laravel's `whenLoaded()` method typically involve unnecessary or unconditional loading of related data, which leads to performance issues such as the N+1 query problem or bloated API responses.

Inefficient Query Designs

1. Unconditionally Loading Relationships in API Resources

A common inefficient pattern is to always include related data in API responses, regardless of whether the client actually needs it. For example, an API resource might always load a user's posts:

php
public function toArray($request) {
    return [
        'id' => $this->id,
        'name' => $this->name,
        'posts' => PostResource::collection($this->posts),
    ];
}

If the `posts` relationship is not eager loaded beforehand, this causes Laravel to execute a separate query for each user to fetch posts, resulting in the N+1 query problem and unnecessary database load.

2. Loading Deep or Nested Relationships Unconditionally

Sometimes deeper nested relationships are loaded without condition, such as loading an article's author and the author's profile or season data, even if the client does not request them. This can cause multiple extra queries and slow down the response.

3. Including Relationship Data in Responses Without Checking If They Are Loaded

Returning relationship data in API responses without confirming if the relationship was loaded can lead to unexpected lazy loading during serialization, triggering extra queries.

How `whenLoaded()` Fixes These Inefficiencies

The `whenLoaded()` method in Laravel API Resources conditionally includes relationship data only if the relationship has been eager loaded. This prevents unnecessary queries and keeps API responses lean.

Example Fix for Unconditional Relationship Loading

Instead of always including posts, use `whenLoaded()`:

php
public function toArray($request) {
    return [
        'id' => $this->id,
        'name' => $this->name,
        'posts' => PostResource::collection($this->whenLoaded('posts')),
    ];
}

If `posts` was not eager loaded, the `posts` key is omitted from the response, avoiding extra queries and reducing response size[1][2].

Example Fix for Conditional Loading Based on Request Parameters

In a controller, dynamically eager load relationships based on client request parameters:

php
$query = Article::query();

if ($request->boolean('with_author')) {
    $query->with('author');
}

if ($request->boolean('with_comments')) {
    $query->with(['comments' => fn($q) => $q->latest()]);
}

$articles = $query->paginate();

return ArticleResource::collection($articles);

Then in the resource:

php
public function toArray($request) {
    return [
        'id' => $this->id,
        'title' => $this->title,
        'author' => new UserResource($this->whenLoaded('author')),
        'comments' => CommentResource::collection($this->whenLoaded('comments')),
        'latest_comment' => $this->whenLoaded('comments', function () {
            return new CommentResource($this->comments->first());
        }),
    ];
}

This approach ensures that only requested relationships are loaded and included, preventing unnecessary queries and data transfer[2].

Avoiding N+1 Queries

By combining eager loading in queries with `whenLoaded()` in resources, you avoid the N+1 problem where each model triggers additional queries for its relationships. `whenLoaded()` ensures that if the relationship is not eager loaded, it is not accessed, thus no extra queries are fired[1][2][3].

Summary

- Inefficient designs load relationships unconditionally or include them in API responses without checking if they are loaded.
- This causes unnecessary database queries, increased latency, and bloated responses.
- Using `whenLoaded()` in API Resources conditionally includes relationship data only if it has been eager loaded.
- This optimizes performance by preventing N+1 queries and reducing data sent over the network.
- Dynamic eager loading based on request parameters combined with `whenLoaded()` provides flexible, efficient APIs tailored to client needs[1][2].

Thus, `whenLoaded()` is a powerful tool to fix inefficient query designs related to relationship loading in Laravel applications.

Citations:
[1] https://laravel-news.com/whenloaded
[2] https://www.interviewsolutionshub.com/blog/laravel-whenloaded
[3] https://www.youtube.com/watch?v=Ls7m14eCaSU
[4] https://stackoverflow.com/questions/49965081/how-do-i-use-whenloaded-for-deeper-than-one-level-relations
[5] https://15799.courses.cs.cmu.edu/spring2025/project1.html
[6] https://stackoverflow.com/questions/3639861/why-is-select-considered-harmful
[7] https://blog.devart.com/how-to-optimize-sql-query.html
[8] https://documentation.solarwinds.com/en/success_center/dpa/content/dpa-table_tuning_advisors.htm