Eager loading select columns with Laravel

Last updated 30th October, 2023

Eager Loading Selected Model Fields

Eager loading is an essential aspect of any Laravel application. Eager loading allows you to tell Laravel to fetch lots of database records ahead of time, saving your application from having to loop over records and perform database connections for each.

Sometimes, you don't need the whole model however. Maybe you have memory overhead issues. Maybe you just want to keep your code as efficient as possible. In any case here's how you can use Laravel to eager load selected columns on a model.

Using The Colon Operator

You can select the columns you want to select from an eager loaded model relation by using a : followed by the comma separated fields you want to select:

$posts = Post::query()
    ->with(['image:id,disk_name'])
    ->get();

The above statement will get all your Post models, and eager load all of the Image models for each of those posts. When performing the select however, Laravel will only fill the id and disk_name fields of the model.

Using The Query Builder

$posts = Post::query()
    ->with(['image' => function (Builder $query) {
        return $query->select('id', 'disk_name');
    }])
    ->get();

Above is the same exact example, but using the slightly more wordy query builder method. This can be useful if you need to perform other logic on the query.

The Full Example

We'll start with the classic Laravel model tutorial example: The Blog. (shocking I know 🤯).

Imagine you have a database structure where a blog post has a single image relation that contains the path to the image, and metadata about that image.

Now if we have say 300 blog posts, that's potentially A LOT of metadata we're going to load. And it might not always be the case that you need it. What we can do in those situations is only pull the columns we need from the database. The result of this will be a reduced memory overhead and a potential speed increase - Laravel won't have to fill hundreds of models with data that might not be used.

In this example your model might look like this:

class Post extends Model
{
    public function image(): HasOne
    {
        return $this->hasOne(Image::class);
		}
}

And when we query the models, instead of this...

Post::query()->with('image')->get();

We use this...

$posts = Post::query()
    ->with('image:id,disk_name')
    ->get();

Simple.

If you need to perform additional checks on the eager load query you can also include this select statement in the longform version in a builder statement:

$posts = Post::query()
    ->with('image' => function (Builder $query) {
        return $query
            ->whereTrue('public')
            ->select('id', 'disk_name');
    })
    ->get();

Conclusion

Its a simple technique, but important to remember. It's very easy to let N+1 and memory issues slip in an application.

Hope this helps 🤙

No comments yet…

DevInTheWild.

Login To Add Comments.

Want More Like This?

Subscribe to occasional updates.

Related Articles