Assume the following two tables (stripped down to this question, assume there is more data on both):
user
id
user_similarity
user_1_id
user_2_id
similarity
I'd like to use user_similarity as a pivot table to construct a list of users that are similar to a given user.
To avoid storing duplicate data on the pivot table, I'd only like one record per user pair, with the lower user ID being stored in the first, and the higher ID in the second column.
Is it possible to set this up without duplicate data records and only a single eloquent relation?
Related
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.
Using Java and Oracle.
We need to update changes in Email, UserID of employee to third party.
Actual table is Employee and intermediate table we keep which we will use for comparison of changes before sending to third party.
Following are database designs coming in mind for intermediate table:
Only Single table:
EmployeeiD|Value|Type|UpdateDate
Value is userid or email, type will be 'email' or 'userid'. Update date is kept so to figure out that which of email or userid was different and update to third party.
Multiple Table:
Employee_EmailID
EmpId|EmailID|Updatedate
Employee_UserID
EmpId|UserID|Updatedate
Java flow will be:
Pick employee from actual table.
Pick employee from above intermediate table.
Compare differences. Update difference to third party.
Update above table with updated value and last update date.
Which one is consider as best way, single table approach or multiple table or is there any standard way to implement the same? There are 10,000 Employees in system.
Intermediate table is just storing Delta records i.e Records transferred to third party so that it can be compared next day.
Good database design has separate tables for different concepts. Using the same database column to hold different types of data will lead to code which is harder to understand, prone to data corruption and less performative.
You may think it's only two tables and a few tens of thousands of rows, so does it matter? But that is only your current requirement. What you choose now will set the template for what happens when (say) you need to add telephone numbers to the process.
Now in future if we get 5 more entities to update
Do you mean "entities", like say Customers rather than Employees? Or do you really mean "attributes" as in my example of Employee Telephone Number?
Generally speaking we have a separate table for distinct entities, and all the attributes of that entity are grouped at the same cardinality. To take your example, I would expect an Employee to have one UserID and one Email Address so I would design the table like this:
Employee_audit
EmpId|UserID|EmailID|Updatedate
That is, I have one record which stores the complete state of the Employee record at the Updatedate.
If we add a new entity, Customers then we have a new table. Simple. But a new attribute like Employee Phone Number offers a choice, because an employee can have more than one: work landline, mobile, fax, home, etc. So we could represent this in three ways: a child table with a type column, multiple child tables for each type, or as distinct columns on the Employee record.
For the main Employee table I would choose the separate table (or tables, depending on whether I'm shooting for 6NF). But for an audit table I would choose one record per Employee and pivot the phone numbers like this:
Employee_audit
EmpId|UserID|EmailID|Landline|Mobile|Fax|Home|Updatedate
The one thing I would never do is have a single table with type and value columns. It seems attractive because it means we could track additional entities without any further DDL. But in fact it becomes harder to re-assemble the complete state of an Employee at any given time with each attribute we add. Also it means the auditing process itself is more complicated (because it needs to determine which attributes have changed and whether it needs to audit the change) and more expensive (because changing three attributes on the same record entails inserting three audit records).
I'm trying to figure out if there's some way to get the values of two columns in a pivot table, based on a unique incrementing ID that I gave each row.
I have a Job model, a Location model, and an Application model.
The Job and Location have a many to many relationship with a pivot table "job_location". The two foreign keys it contains are job_id and location_id. However, I also gave every row a unique incrementing ID, jobloc_id.
If I only have the jobloc_id, how can I look up the values of the other two columns?
$jobLoc = $location->jobs->wherePivot('jobloc_id', '=', 1);
return $jobLoc->job_id;
Returns "Method wherePivot does not exist" even though I've seen references of people using it. All I have is the jobloc_id, and am trying to lookup the other two values based on this so that I can fully load the Job and Location to pull attributes from them.
Any pointers would be greatly appreciated. This is in Laravel 5.3.
If you're added ID to pivot table (jobloc_id for example) and you want to get row by ID, just use query builder:
DB::table('job_location')->where('jobloc_id', 1)->first();
That's the fastest and simpliest way to do that when you have unique row ID in the pivot table.
I have relation many to many (posts and tags) in Eloquent. Is it possible to order tags in the pivot table to get 10 most commonly used tags?
Yes it is possible, add some kind of attribute (to the pivot table and update it upon every select from the database. (increment the value)
And when selecting use wherePivot method.
If you want "most recent used", add timestamps to the pivot table in your migration and touch pivot table on every select.
Yes it is actually very simple to do that.
In the table that you store your tags add another column called count_cache(or whatever you want), then every time you add a tag instance to a post instance do a count() of the tag_id in the pivot table and store the value to the count_cache column in the tags table.
Then you can simply get the tags table ordered by the count_cache collumn (descending) with a limit of 10.
If you need further explanation please make a comment :)
I'm using CodeIgniter and I'm starting to work with gas orm.
One of my m-n-relationship-tables using a composite key has also some additional attributes to the releation.
For Example:
Table teams, Table employees, and a m-n table which binds them together + adding the attribute role
Is it possible to get the attribute using GAS ORM?
Yes, it is possible.
Simply create a new relationship in one of the two tables you are going to link with the pivot table that refers to the pivot table itself as a has_many relation. (But dont do the linking stuff in the model file, eg:
ORM::has_many('\\Model\\User\\Role')
instead of
ORM::has_many('\\Model\\User\\Role => \\Model\\Role')
See http://ellislab.com/forums/viewreply/1050559/ for exact the same question.