rodrigoriome's avatar

Use already loaded data when eager loading

What is the Laravel way to use already loaded data when defining relations?

Here is what I mean...

$states = \App\Models\State::all();
$cities = \App\Models\City::with('state')->get();

The code above will yield 3 queries:

  • One query to load everything from the states table
  • One query to load everything from the cities table
  • One query to load records from the states table associated to each City

But I've managed to use only 2 queries by manually setting the relationship, like so:

$states = \App\Models\State::all();
$cities = \App\Models\City::all()->map(function ($item) {
    $item->setRelation('state', $states->where('id', '=', $item->state_id)->first());

    return $item;
});

Is there any Collection method that can make life easier when dealing with this scenario?

Thanks

0 likes
1 reply
LaryAI's avatar
Level 58

One solution to this problem is to use the keyBy method on the $states collection to create an associative array with the state IDs as keys. Then, when eager loading the state relationship on the $cities collection, Laravel will use the already loaded data from the $states collection instead of querying the database again.

Here's an example:

$states = \App\Models\State::all()->keyBy('id');
$cities = \App\Models\City::with('state')->get()->map(function ($city) use ($states) {
    $city->setRelation('state', $states->get($city->state_id));
    return $city;
});

In this example, we first load all the states and use the keyBy method to create an associative array with the state IDs as keys. Then, we load all the cities with the state relationship eager loaded. Finally, we use the map method to loop through each city and set the state relationship using the already loaded data from the $states collection.

Note that we use the get method on the $states collection to retrieve the state with the given ID. This method returns null if the key is not found, which is why we need to use the setRelation method instead of the associate method to set the relationship.

Please or to participate in this conversation.