How to access model hasMany Relation with where condition?
Stefan Izdrail
Founder & Senior Architect · 2026-06-29
Title: Accessing Model Relationships with Conditions - A Comprehensive Guide for Laravel Developers
Introduction: In the world of Laravel development, efficient database handling is crucial to building robust applications. To achieve this efficiently, Laravel provides a number of useful relationship functions in terms of hasMany (one-to-many) relations. However, accessing these relationships with conditions can sometimes be tricky. This blog post aims at tackling that issue and providing an effective solution for developers using Laravel's relationship functions.
Understanding the Problem: In the example provided above, the problem lies in accessing data from the 'available_videos()' relationship without eager loading. When trying to access this relation without eager loading, an exception occurs due to a non-object response. This issue is caused by the fact that hasMany relationships in Laravel are essentially collections of objects. Therefore, when using a where condition and retrieving data from the collection as a single model, the call to 'count()' will fail as there is no object to count but only an array.
Best Practices: There are several ways to solve this issue, depending on your specific need. Here are some suggestions that work well in different scenarios:
1. Eager Loading: If you need access to all the available videos of a particular game, eager loading is the most efficient way. By using 'with()' or 'load()', you can load associated relationships along with your primary model query. This will ensure that related models are retrieved and available for use without any issues.
$game = Game::with('available_videos')->find(1);
$count = $game->available_videos->count();
This example loads the available videos for a specific game (Game model) and fetches the count of these videos. Eager loading is an excellent choice when you need to access all related models at once.
2. Lazy Loading: If you only need to perform an operation on one or more items in the collection, you can use 'load()' followed by an iteration through your primary model results. This approach will not load associated models until they are needed, making it resource-efficient.
$game = Game::find(1);
$game->load('available_videos');
foreach ($game as $g) {
// process games and their available videos
}
This example demonstrates lazy loading, where the 'available_videos' relation is loaded only when needed. This approach is handy when you need to work with just a few models or perform operations on individual items.
3. Dynamic Relation Loading: The Laravel documentation recommends using dynamic loading for this specific scenario. By creating a new query and performing an inner join, you can ensure that only the models that meet your criteria are loaded. This method requires more code but also offers greater flexibility when working with relationship constraints.
$availableVideos = Video::where('game_id', $gameId)
->where('available', 1) // if you want to include only available videos
->join('games', 'videos.game_id', '=', 'games.id')
->select('videos.*', 'games.title as game_title')
->get();
This approach allows you to load only the necessary records and maintain data efficiency. It is quite useful when dealing with complex queries or multiple constraints in your relationships.
Conclusion: Accessing model relations with conditions can be tricky, but it's possible through various methods. You can use eager loading for all-at-once access or lazy loading for when you need one at a time. If you have more constrained requirements, dynamic relation loading might be the best option. In any case, remember to stay flexible and adapt your techniques based on your project's needs.
To make this even clearer, let's add more examples in code snippets for each approach:
Eager Loading Example:
$game = Game::with('available_videos')->find(1);
foreach ($game as $g) {
$availableVideosCount = $g->available_videos->count(); // count available videos for this game
}
Lazy Loading Example:
$game = Game::find(1);
$game->load('available_videos');
foreach ($game as $g) {
// process games and their available videos
}
Dynamic Relation Loading Example:
$availableVideos = Video::where('game_id', $gameId)
->where('available', 1) // if you want to include only available videos
->join('games', 'videos.game_id', '=', 'games.id')
->select('videos.*', 'games.title as game_title')
->get();
foreach ($availableVideos as $video) {
// process videos and their associated games
}
Remember, no solution is perfect in every situation. It's essential to pick the one that aligns with your project's needs and goals.