Laravel Eloquent: Eager Load Pivot Relations

Arjon Jason Castro
3 min readApr 23, 2019

--

In Laravel, we can create our custom pivot models. Our pivot model can also contain relations and we can access them in the pivot property. By using the package ajcastro/eager-load-pivot-relations, we can eager load the relations in our pivot model.

For example, in a procurement application, we have the following:

Tables:

items
- id
- name
units
- id
- name (pc, box, etc...)
plans (annual procurement plan)
- id
plan_item (pivot for plans and items)
- id
- plan_id
- item_id
- unit_id

Models:

class Unit extends \Eloquent {
protected $fillable = [];
}
class Item extends \Eloquent
{
protected $fillable = [];
public function plans()
{
return $this->belongsToMany('Plan', 'plan_item');
}
}
class Plan extends \Eloquent
{
protected $fillable = [];
public function items()
{
return $this->belongsToMany('Item', 'plan_item')
->using('PlanItem')
// make sure to include the necessary foreign key in this case the `unit_id`
->withPivot('unit_id', 'qty', 'price');
}
}
// Pivot model
class PlanItem extends \Illuminate\Database\Eloquent\Relations\Pivot
{
protected $table = 'plan_item';
public function unit()
{
return $this->belongsTo('Unit');
}
}

We can access unit relation from the pivot model PlanItem by doing something like this:

$plan = Plan::with('items')->find($id);foreach ($plan->items as $item) {
$unit = $item->pivot->unit;
echo $unit->name;
}

However, this will produce N+1 query because it accesses the unit model one-by-one. We can solve that by eager loading the relations in the pivot model.

So we need to install and use our package to do that:

composer require ajcastro/eager-load-pivot-relations

Then let’s use the AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait in the belongsToMany relation model which is the Item model.

use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;class Item extends \Eloquent
{
// Use the trait here to override eloquent builder.
// It is used in this model because it is the relation model
// defined in Plan::items() relation.
use EagerLoadPivotTrait;
}

Voila! We can now eager load the pivot relations. Use keyword pivot in eager loading pivot models. So from the example above, we can do it by doing like this:

$plan = Plan::with('items.pivot.unit')->find($id);
// or
$plans = Plan::with('items.pivot.unit')->get();

Our json structure will look like this:

You can also add more relations in the pivot model if necessary and you can also chain more relations in eager loading.

return Plan::with([
'items.pivot.unit',
'items.pivot.unit.someRelation',
'items.pivot.anotherRelation',
// It is also possible to eager load nested pivot models
'items.pivot.unit.someBelongsToManyRelation.pivot.anotherRelationFromAnotherPivot',
])->get();

This way, we can easily work with any BelongsToMany relations which include more than one related model without changing our main belongsToMany data structure.

Related SO Post: https://stackoverflow.com/a/55807381/5191738

If you find this post helpful to you, you might want to buy me just a little coffee. Thanks! 😉

Happy Coding!!! 😊😊

--

--

Responses (4)