Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Eager Loading: Use `with` on pivot with eloquent relationship

There are 4 tables:

  • bundles: id, name
  • products: id, name
  • prices: id, name
  • bundle_product: id, bundle_id, product_id, price_id

There are 3 models:

  • Bundle
  • Product
  • Price

A Product has a Price when in a Bundle. I want to have all bundles with their associated products and associated prices. I can get all bundles with their product and the price id:

// I created a Bundle Model with a products method
class Bundle extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class)->withPivot('price_id');
    }
}

// Then I call this in a controller
$all_bundles = Bundle::with('products')->get();

// Then I can get the price Id of the first product of the first bundle
$price_id = Bundle::with('products')->first()
    ->products()->first()
    ->pivot->price_id;

But I dont want the price id, I want the price Model. Is there any way to preload the price from the pivot (with Eager Loading)?

like image 584
rap-2-h Avatar asked Jun 01 '16 14:06

rap-2-h


People also ask

How does eager loading work?

At its core Eager Loading, is telling Eloquent that you want to grab a model with specific relationships that way the framework produces a more performant query to grab all the data you will need. By eager loading, you can take many queries down to just one or two.

What is difference between eager and lazy loading Laravel?

The main difference between eager and lazy loading is eager loading get all data with relationship records in single query and lazy loading require N+1 queries for getting main model and relation data. Eager loading run single query whereas lazy loading run N+1 queries.

How does eager loading work Laravel?

Eager loading is a concept in which when retrieving items, you get all the needed items together with all (or most) related items at the same time. This is in contrast to lazy loading where you only get one item at one go and then retrieve related items only when needed.

How do I get pivot table data in Laravel?

On the relationships for both User and Target , tack on a ->withPivot('type') which will instruct Laravel to include that column. Then once you have your result set, you can access the field with $user->pivot->type .


1 Answers

The current accepted answer deviates from the original data structure. I created a package which can help you achieve what you want and also it maintains the original data structure. Please read my medium story here: https://medium.com/@ajcastro29/laravel-eloquent-eager-load-pivot-relations-dba579f3fd3a

First, create your custom pivot model and define relations on pivot model, in your case:

use Illuminate\Database\Eloquent\Relations\Pivot;

class BundleProduct extends Pivot
{
    public function price()
    {
        return $this->belongsTo(Price::class);
    }
}

Then use the pivot model in the relation:

class Bundle extends Model
{
    public function products()
    {
        return $this->belongsToMany(Product::class)
        ->withPivot('price_id') // this is needed to query the relation `price`
        ->using(BundleProduct::class);
    }
}

Make sure you use the trait AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait in the Product model because it is the related model in belongsToMany relation. This let us enable eager loading the pivot relations.

use AjCastro\EagerLoadPivotRelations\EagerLoadPivotTrait;

class Product extends Model 
{
  use EagerLoadPivotTrait;
}

Then eager load it like this:

$bundle = Bundle::with('products.pivot.price')->first();
$price = $bundle->products->first()->pivot->price;
like image 171
Arjon Jason Castro Avatar answered Oct 22 '22 04:10

Arjon Jason Castro