Your Municipality - City probably belongsTo , and not hasMany , as in the paste.
In any case, you can use the hasManyThrough relation to access a significantly related collection:
Country - City Province - Municipality
Unfortunately, there is no relationship for level 3, so you cannot do it that way.
Then your code with whereHas does not limit provinces to west and municipalities to 9000+ , but limits countries those associated with them. In your case, this means that the result will be either Country (if its relationship meets these requirements), or null otherwise.
So, if you really want to limit related collections, you will need this part:
$country = Country::with(['provinces' => function($query){ $query->where('location', 'West'); }, 'provinces.cities.municipalities' => function ($query){ $query->where('population', '>', 9000); }])->find($country_id);
This application requires intensive download restrictions, and what it does:
1. loads only West provinces for country with id 1 2. loads all the cities in these provinces 3. loads only 9k+ municipalities in these cities
Since you are not interested in cities, you can use hasManyThrough in the province:
// Province model public function municipalities() { return $this->hasManyThrough('Municipality', 'City'); }
then
$country = Country::with(['provinces' => function($query){ $query->where('location', 'West'); }, 'provinces.municipalities' => function ($query){ $query->where('population', '>', 9000); }])->find($country_id);
However, in both cases, you cannot directly contact the municipalities, but only this way:
// 1 classic $country->provinces->first()->cities->first()->municipalities; // 2 hasManyThrough $country->provinces->first()->municipalities;
If you want to work with all these municipalities, you need this trick:
$country = Country::with(['provinces' => function($query){ $query->where('location', 'West'); }, 'provinces.municipalities' => function ($query) use (&$municipalities) { // notice $municipalities is passed by reference to the closure // and the $query is executed using ->get() $municipalities = $query->where('population', '>', 9000)->get(); }])->find($country_id);
This will cause an additional request, but now all the municipalities are in a single, flat collection, so it is very easy to work with it. Otherwise, you are likely to get a bunch of foreach loops.