Laravel models, database and pivot tables question - laravel

Hello I am working with Laravel,
I have to create two simple models, let's say Stores and Books.
Stores can have one or multiple Books and Books can belong to many Stores.
Of course I will use a many to many relationship, with a pivot table.
Books the can have different prices depending the store.
I think a separate table can only complicate things, in my mind the pivot table associating books and stores should have a price column, but pivot tables only contains store_id and book_id.
Should I create a book_prices and associate it with books and to stores? What is the best approach?

You are free and able to set other attributes on your pivot table. You can read more about it in the docs.
https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns
You have to define the relationship accordingly, the following should clarify how this works. In this example you use the many-to-many relationship and add the price column to every retrieved pivot model.
public function books()
{
return $this->belongsToMany(Book::class)
->withPivot('price')
}
For example, you are able to access the pivot column in a loop like this
foreach ($shop->books as $book)
{
echo $book->pivot->price;
}

You can define additional columns for your pivot table in the migration for the pivot table, and then when defining the relationship use withPivot to define the additional columns so they come through in the model:
return $this->belongsToMany(Book::class)->withPivot('price');
(Adapted from the Laravel documentation, see https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns)

Depends on the complexity of your case, but yes, you have two options for it. Let's say that the pivot table is called as book_store:
Directly adds price column to book_store. This is obviously the simpler option. The drawbacks are:
The history of the price changes isn't logged. You'll have to create another table for logging if you want to keep this history information.
Changes made to price will directly change the price of the related book_store record. Meaning that a price is being updated "live" e.g users cannot update the price now but "publish" it some time later just like this example in the doc.
Create a new, different table to store the price. This may seems relatively more complex, but it may also be more future-proof.
Basically, you get 2 things that you miss in the first option above.
Don't think too much about book_store being a pivot table. One way to see it is like this: book_store IS a pivot table from books and stores tables viewpoints, but it's also just a normal SQL table which could relate to any other tables using any kind of relationships.
If you want to implement this, make sure to create a primary-key in the book_store table.
Alast, it all depends on what you need. Feel free to ask if you need more insight about this. I hope this helps.

Related

Is it best practice to use a pivot table with many to many relationship when a model and 2 one to many relationships might make sense?

This is more of a best practices question. I am making a game where factions can upgrade their technology for their faction. So I have a faction table which stores the faction name and id and a tech_upgrades table which stores the possible tech upgrades along with their costs. Then I have another table which stores the progress each faction has made towards their tech upgrades which is the faction_tech_upgrades table. So there should be a row in faction_tech_upgrades for every combination of faction and tech_upgrade. This kind of looks like a pivot table with extra data similar to https://laravel.com/docs/9.x/eloquent-relationships#retrieving-intermediate-table-columns
My dilemma involves how to set up the eloquent relationships. My gut says to use option 1 but just wanted to make sure I'm not setting these up poorly. So any advice on best practices is appreciated. Here are the 2 options I think make sense.
Option 1:
Create a model for faction_tech_upgrades. Then set up a one to many relationship between factions and faction_tech_upgrades, and set up a one to many relationship between tech_upgrades and faction_tech_upgrades. The reasoning here is that the faction_tech_upgrades table is functioning as more than just a pivot table so maybe making a model for it makes sense, as it might be easier to work with in terms of updating and querying the table.
Option 2:
Set faction_tech_upgrades up a as a pivot table and use the above link to get the data from that table. And use https://laravel.com/docs/9.x/eloquent-relationships#updating-a-record-on-the-intermediate-table to update the table.
factions columns
id,
name,
color,
created_at,
updated_at
tech_upgrades columns
id,
name,
description,
class,
order,
type,
gold_cost,
iron_cost,
wood_cost,
emerald_cost,
pink_tourmaline_cost,
turquoise_cost,
created_at,
updated_at
faction_tech_upgrades columns
id,
faction_id,
tech_upgrade_id,
unlocked,
gold_contributed,
iron_contributed,
wood_contributed,
emerald_contributed,
pink_tourmaline_contributed,
turquoise_contributed,
created_at,
updated_at
Any advice or other options appreciated.
If you have more than 2-3 extra fields in a pivot table, its better to create an another model and make one to many relationship as you describe in option one. It will will be easy to insert and update data. But if you follow the Laravel pivot table naming convention you will get extra benefit for easy access of the data.

Inverse of belongsToMany

I got two Models:
Order
Invoice
Each Order can have many Invoices - and an Invoice can belong to many Orders.
So I can search for an Order and check: "Hey, which Invoices have been created for this Order?"
The other way round each Invoice can belong to multiple Orders, because maybe a customer ordered two products on the same day and so it would be great he'd only get one Invoice, which includes both orders.
So this is how I did this:
Invoice
public function orders()
{
return $this->belongsToMany(Order::class);
}
Order
public function invoices()
{
return $this->belongsToMany(Invoice::class, 'invoice_order');
}
This does work - but it does not seem right to change the table to the intermediate table invoice_order here. Do you have any thoughts on this? :-)
Thanks in advance for your thoughts :-)
Seperating the relation into a seperate pivot table is the commonly used method in laravel (and in most other frameworks) for many to many relationships.
It's easy to maintain, easy to get related models using many to many relationship, and if someone else needs to work on it in the future, they'll probably have used it in the past as well so wouldn't end up burning their heads.
The other method you could use is to create a json column on one of the tables (you can create on both tables as well if you want, but that's just extra overhead). Then you can store the ids of the related models in this json column. You can then join the tables using the json related commands provided by your database. Eloquent does not support relationships on json, but you can use this package staudenmeir/eloquent-json-relations to build relationships on json fields.
So overall, I'd suggest keeping a pivot table like the standard way, but if that just won't do, then you can try the json column method

how do I make relationships for 4 tables including pivot table

I have many to many relationships. Imagine I have 3 tables. Something like this :
users.
roles.
role_user.
(This example is also provided in laravel's docs).
Now I'm doing this : $user->roles() which returns roles with Pivot attributes . but what I actually want to do is move forward and also get the appropriate data from the 4th table. something like this $user->roles()->types(); and the difficult thing is that this types() belongs to pivot table.
Do you know how to do this kind of thing ? where Do I write types() function?
Assuming your "Roles" model has the relationship set you may try
$user->roles()->with("types")
Source docs: https://laravel.com/docs/5.7/eloquent-relationships#eager-loading

One for all or individual Pivot for every many to many in Laravel?

i dont know that i'm doing right or wrong..
i want to make a blog that have multiple categories and tags with many to many relation.
should i make a pivot table for each one like:
"category_post"
$table->integer('post_id')->unsigned()->index();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->integer('category_id')->unsigned()->index();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
and another one for Tags table...
or can i make one table for both with an extra column that can filter throw that?
"pivot_post"
$table->integer('post_id')->unsigned()->index();
$table->integer('pivot_id')->unsigned()->index();
$table->string('type');
but.. if i can make one for all, i dont know hot make db and relation??
and which one is better for performance..?
1 big relation tableor multiple relation table?
tnx.
I think you're looking for a polymorphic relationship if you wanna accomplish this with a single table.
https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations

Modeling many-to-many relationship in data warehouse

I have to design data warehouse model and ETL process for class at my University. My data warehouse has to store opinions / comments about a product, each record should consist of:
comment text (String)
product score ({0, 0.5, … , 4.5, 5})
comment author (String)
comment date (Date)
product recommendation ({Yes, No})
comment up votes (Int)
comment down votes (Int)
product pros (many Strings, e.g {price, design, durability, … }) and its count
product cons (many Strings, e.g {too loud, too heavy, price, … }) and
its count
In addition data warehouse should store information about product:
product category
product brand
product model
I want to create data warehouse model first, but I have problem with storing product pros and cons as it is many-to-many relationship. In normal relational database I would simply create associative table, but here I am not sure how to proceed, after all I don’t want to normalize facts table.
I am considering 3 approaches, first, which I presented in diagram below. I used bridge table method (though, I don’t know if correctly) to get rid of many-to-many relationship. I don’t know how it will impact querying performance.
Second approach I may use is boolean column method. In PROS and CONS table I can create a column for each possible value, but there can be up to 100 different pros or cons. Also number of possible pros or cons is not constant in time. Authors in their comments can list new pros or cons (that’s how it works in data source), but I can’t add new columns (I shouldn’t change data in data warehouse).
Third approach I am considering, is to keep pros in PROS table but in 1 column, where values will be separated using commas or some other delimiter e.g. “price, design, color”. It keeps things simple but hard to analyze or slice & dice.
Which approach should I use in this situation? Which is better for loading data into data warehouse, because form data source I will get all the comments and I want to only load comments that are new since last loading?
What I think is, if we can get your first option little bit modified to than what you have said here, it would be the best as I understand.
in your image you have provided, having the Pros_Bridge_Detail table is fine. The rest need to be changed.
you can remove the pros_Bridge table that holds just the count. you can actually add that column to your COMMENT fact table you have up there. That would be more efficient and easy when it comes to queries rather than querying in many tables.
you said you have many areas to give pros like price, design, durability etc. Lets put those stuff into a separate dimension.
Add a new column to your Pros_Bridge_Detail table to hold the ID of the newly created Dimension that holds the product pro types (Design, durability etc).
Now, once you add a product Pro, the Pros_Bridge_Detail table will have the pros the user give and also hold the value of regarding what the pro is given via the ID of the new dimension.
Also don't forget to store the Comment ID as well in Pros_Bridge_Detail table as that will be your link (FK) to Comments fact table you have.
Same can be done to Cons as well.
Hope you understand what I just explained and hope it helps. let know if you have any issues.

Resources