Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

Pivot Tables and Extra Field Operations

Premium
5 min read

Let's discuss a feature of Laravel that is useful but potentially difficult to understand at first. A pivot table is an example of an intermediate table with relationships between two other "main" tables.


Real-life Example of Pivot Tables

Let's say a company has a dozen Shops all over the city/country and a variety of products, and they want to store information about which Products are sold in which Shops. It's a perfect example of a many-to-many relationship: one product can belong to several shops, and one shop can have multiple products.

So here's a potential database structure:

The product_shop table is called a "pivot" table.


Managing Many-to-Many Relationships: attach-detach-sync

How do we save the data with the help of our two Models instead of the third intermediate one? A couple of things here. For example, if we want to add another product to the current shop instance, we use relationship function and then method attach():

$shop = Shop::find($shop_id);
$shop->products()->attach($product_id);

A new row will be added to the product_shop table with $product_id and $shop_id values. Likewise, we can detach a relationship - let's say we want to remove a product from the shop:

$shop->products()->detach($product_id);

Or, more brutally, remove all products from a particular shop - then call the method without parameters:

$shop->products()->detach();

You can also attach and detach rows by passing an array of values as parameters:

$shop->products()->attach([123, 456, 789]);
$shop->products()->detach([321, 654, 987]);

Another beneficial function, in my experience, is updating the whole pivot table. For example, your admin area has checkboxes for shops for a particular product. During the Update operation, you must check all shops, delete those not in the new checkbox array, and then add/update the existing ones. Pain in the neck. Not anymore - there's a method called sync() which accepts new values as parameters array and then takes care of all that "dirty work" of syncing:

$product->shops()->sync([1, 2, 3]);

Result - no matter what values were previously in the product_shop table. After this call, there will be only three rows with shop_id equals 1, 2, or 3.


Additional Columns in Pivot Tables

As mentioned above, you would want more fields in that pivot table. In our example, saving the amount of products and price in that particular shop and timestamps makes sense. We can add the fields through migration files, as usual, but for proper usage in relationships, we have to make...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (29 h 14 min)

You also get:

54 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Comments & Discussion

SA
Stephan Apenbrink ✓ Link copied!

Hi everyone, I have a Problem with this function

public function products(): BelongsToMany { return $this->belongsToMany(Product::class) ->withPivot(['products_amount', 'price']) ->withTimestamps(); }

	If I call this like :
	 $shop=App\Models\Shop::with('products')->get();
	 
	 and make the loop :

foreach ($shop->products as $product);
	{
		echo $product->pivot->price;
	}	 
	
	I get an Error : Property [products] does not exist on this collection instance.
	
	But it does : 
	
	#relations: array:1 [▼
    "products" => Illuminate\Database\Eloquent\

Collection {#1234 ▼

Where am I wrong ?

Thanks in Advance, Stephan

M
Modestas ✓ Link copied!

You are retrieving all shops, therefore you need two loops:

foreach($shops as $shop) {
	foreach($shop->products as $product) {
		// Your code
	}
}

If you need jsut one shop model, then replace ->get() with either ->find($id) or ->first(). Depending on your case.


In other words, you are trying to access products on a collection of multiple items - which does not exist. Instead you need to take single item and access it's products.

SA
Stephan Apenbrink ✓ Link copied!

Thx a lot for the help ! Learning has to go on.

SS
Stefan Sperling ✓ Link copied!

Using the term 'pivot table' is very confusing if you have a background in data analysis and database design. A pivot table is used to aggregate data for a diverse number of calculations. The term correct database term is 'cross reference (x-ref)' table which describes the function of such tables much better imho. Why didn't the designers of Laravel/Eloquent pay more/better attention to such conventions?

M
Modestas ✓ Link copied!

Hard to say why this was their choice :)