I am struggling between to database designs:
I have Table A (Metrics) where stored app metrics for different dates and from different networks.
id
app_id
network
date
param1
param2
...
1
A_123
A
2020-12-01
2
C_123
C
2020-12-01
3
B_123
B
2020-12-01
4
A_123
A
2020-12-02
5
A_123
A
2020-12-03
5
A_456
A
2020-12-01
5
A_456
A
2020-12-02
5
B_456
B
2020-12-02
A_123, B_123 and C_123 is same app, but comes from different network, that's why I want to create mappings to give a common name.
And I have Table B (Mapping table)
id
app_id
name
1
A_123
App Name 1
2
B_123
App Name 1
3
C_123
App Name 1
4
A_456
App Name 2
5
B_456
App Name 2
Now I have One To Many (Inverse):
public function mapping() {
return $this->belongsTo('App\Models\Mapping', 'app_id', 'app_id');
}
but operations like update mapping data, seems a little difficult and not correct, because if I want to change mapping name and remove some app_id, I need to collect all TableB.id and pass it to script. And easier is just to delete([1,2,3]) and create 3 new records with new App name.
Then I thought that this is probably Many-To-Many, but seems not, because for example in Metric table for each app_id I have 10k records and if I want to map 4 id to 1 name, then for 1 mapping in table mapping_metric table would be 40k records.. and this seems is even worse then first design..
And my final thoughts, that if both methods are not working well, then probably my Metrics table not designed well or something else.
Do you have some ideas or you know some approach how can I map ids to name?
First for a good database design as our friend suggested your table have to be normalized so i suggest this illustration:
A table name apps
A table name networks
A pivot table name app_table
A table name metrics
and the relationship between them should be like:
apps belongsToMany networks (pivot:app_table)
networks belongsToMany apps (pivot:app_table)
apps hasMany app_table
app_table belongsTo apps
networks hasMany app_table
app_table belongsTo networks
app_table hasMany metrics
metrics belongsTo app_table
the only important thing is you have to make a model for your pivot itself
class App extends Model{
/**
* retrive networks
*
* #return BelongsToMany networks
*/
public function networks()
{
return $this->belongsToMany(App\Network::class, "app_table", "app_id", "network_id")
->withPivot("deleted_at")
->using(App\AppNetwork::class);
}
/**
* retrive app_networks
*
* #return hasMany [description]
*/
public function appNetworks()
{
return $this->hasMany(App\AppNetwork::class, "app_id")->withTrashed();
}
}
The Network Model Would be the Same with inverse relations.
but for pivot table model you have to extend from Illuminate\Database\Eloquent\Relations\Pivot and set public $incrementing = true; to increment id automatic
class AppNetwork extends Pivot
{
public $incrementing = true;
public function network()
{
return $this->belongsTo(App\Network::class);
}
public function app()
{
return $this->belongsTo(App\App::class);
}
public function metrics()
{
return $this->hasMany(App\Metrics::class, "app_network_id");
}
}
this were the primary relations that you can define in your for models.
for more complex relation you can define them using this tools:
hasManyThrough
eloquent join with getNamedAttribute or Laravel Scope
BelongsToThrough.
Related
I have an understanding issue with Laravel Eloquent Models and relations.
I have a user table user. These users can add car license plates, which I save in user_plates. I have a database which contains car models and types. The table name is cars. I have the models App\User, App\UserPlates and App\Car.
The user_plates table has the fields id,plate,user_id,car_id.
I save the plate, the associated user (in user_id) and the selected car (car_id (id from table cars))
I added plates() with belongTo function to my User Model which already successfully returns all plates associated with that user. But now I want to get the associated car (car_id inside user_plates). How do I achieve this using Eloquent? The car table does not have any connection to the user table, only user_plates has a car_id and a user_id.
I need to achieve this:
User -> Plates (can be multiple) -> Plate -> Car. I know how to achieve this using simple MySQL Joins but I want to do it right with Eloquent. Thanks for any help!
Laravel: 6.4.0
So, if your database is set up as...
users user_plates cars
----- ----------- ----
id id id
etc. plate etc.
user_id
car_id
Your models are set up as...
// in model: User
public function user_plates()
return $this->hasMany('UserPlate'); // fill out fully qualified name as appropriate…
// in model: UserPlate
public function user()
return $this->belongsTo('User');
public function car()
return $this->belongsTo('Car');
// in model: Car
public function user_plates()
return $this->hasMany('UserPlate’);
To return a collection of cars belonging to user $id you should be able to run:
$cars = User::findOrFail($id)-> user_plates->pluck('car');
I have two models/tables: publisher and campaign.
Publisher
id | name
Campaign
id | name | PubID
I created a relationship to get the Publisher's campaigns.
$this->hasMany(Campaign::class, 'PubID'); /* In Publisher Model */
I believe the above line will help me to retrieve relevant campaigns, but I'm confused about the inverse relationship.
As you can see, there is no key campaign_id inside the publisher table. Would the below relationship be enough for the inverse?
return $this->belongsTo('App\Publisher'); /* In Campaign Model */
Can someone kindly guide me? I would appreciate it.
Yes, this is so called one to many relationship, which means one publisher has many campaigns. And the inverse is that a campaign belongs to a publisher.
So in order to get all the campaigns for the publisher you use:
Publisher::find($id)->campaigns;
In order to get what is the publisher of the campaign, you use:
Campaign::find($id)->publisher;
You don't need campaign_id inside the publisher table, that is known by the PubID in your campaign table.
You have two models and adding two foreign id. It is a many to many working. You just need add pivot table with campain_id and publiser_id
It’s a perfect example of many-to-many relationship: one publisher can belong to several campains, and one campains can have multiple publisher.
publishers
ID | NAME
campaigns
ID | NAME
campaign_publisher
campain_id | publisher_id
The final table in the list – campaign_publisher is called a “pivot” table, as mentioned in the topic title.
So, option 1:
class Campaign extends Model
{
/**
* The products that belong to the shop.
*/
public function publishers()
{
return $this->belongsToMany('App\Publisher');
}
}
So, option 2:
class Publisher extends Model
{
/**
* The shops that belong to the product.
*/
public function campaigns()
{
return $this->belongsToMany('App\Campaign');
}
}
You ,eed to specify the foreign key name in the belongsTo
return $this->belongsTo('App\Publisher','PubID');
Laravel Relationships
Is it possible to seed related tables using the following in Laravel 5?
php artisan db:seed
I have two tables
users
id
first name
projects
id
name
and a pivot table
project_user
project_id
user_id
I would like to create a number of users, a number of projects and then relate the users and their respective projects.
Seeding the users and projects isn't a problem but I am not sure how to handle the pivot table.
Is it possible?
Of course you can. If you are using Eloquent, you can simply work with normal relations (maybe the easiest way). Or if you use the SQL builder directly, you can feed the table just as normal, but you need to stick to your foreign key rules.
Just give in a try and you'll see. But make sure you import classes you use.
Adding a relation between two models is easy, but there are some differences between the common relation types (and he perspective): one-to-many, many-to-one and many-to-many.
One-to-Many and Many-to-One
Assumed that each of your project has a creator, an owner so-to-say, you could have a 1:n relation between User and Project.
public class User {
public function ownedProjects() {
return $this->hasMany('App\Project');
}
}
public class Project {
public function owner() {
return $this->belongsTo('App\User');
}
}
In this relation, you can either attach a Project to a User or tell the Project who his owner is.
// Attach a project to an user
$project = Project::create([]);
User::find($id)->ownedProjects()->save($project);
// There is also a function saveMany() for an array of projects
// Tell the project who his owner is
$project = Project::create([]);
$project->owner()->associate(User::find($id));
Many-to-Many
In your case, we need a Many-to-Many relation between Users and Projects. The syntax is a bit different, but the outcome quite straight forward. First we need a relation between the both models:
public class User {
public function projects() {
return $this->belongsToMany('App\Project');
}
}
public class Project {
public function users() {
return $this->belongsToMany('App\User');
}
}
Then we can query the relation just like that:
$project = Project::create([]);
User::find($id)->projects()->attach($project->id);
You can also attach a whole bunch of projects, do the same things from the other side, detach models or synchronize them, if you want to make sure that an exact amount (and only this amount) is in relation:
// Adds a relation for the user to projects with ids 1, 2, 4 and 6
User::find($id)->projects()->attach([1, 2, 4, 6]);
// Adds the users with ids 19 and 173 to this project
Project::find($id)->users()->attach([19, 173]);
// Removes the user 19 from the projects relations
Project::find($id)->users()->detach(19);
// Removes all relations between this user and projects that are
// not listed in the synchronization array and adds a relation
// to all projects where none exists yet
User::find($id)->projects()->sync([4, 7, 19, 6, 38]);
This is the normal syntax for Many-to-Many relations, but you can also attach models just like in a One-to-Many relation:
// Creation of project could also be done before and saved to a variable
User::find($id)->projects()->save(Project::create([]));
I am trying to find out the best way to define the following relation using Laravel's Eloquent Laravel.
I have a User table and 3 Objects ( Player, Team, League) that the user can add as favorites.
I know I can create three pivot tables with the User Model and each one of the objects but then I will need to run a Union query to list all favorites from user regardless of type.
User
id
Favorite
id
user_id
favorited_id ( player_id or team_id or league id)
favorite_type ( player , team or league)
Player
id
Team
id
League
id
Here is my model.
https://www.dropbox.com/s/6au8giufaejcghc/Screen%20Shot%202014-04-07%20at%209.06.51%20AM.png
i'd do it the same with a Favourite table. laravel covers this with its polymorphic relations.
your tables could look like
class Favourite extends Eloquent {
public function favourable()
{
return $this->morphTo();
}
}
class Team extends Eloquent {
public function favourite()
{
return $this->morphMany('Favourite', 'favourable');
}
}
...
your Favourite table would look like
Favourite
favourable_id: int
favourable_type: string
you'd call it like a normal property on the model like $player->favourable().
You can either use polymorphism as suggested by user3158900, or my preference would be to use Laravel's Query Builder to perform the Union query.
http://laravel.com/docs/queries#unions
$first = DB::table('users')->whereNull('first_name');
$users = DB::table('users')->whereNull('last_name')->union($first)->get();
I'm trying to create a polymorphic relationship with multiple pivot tables. I have a table of requirements that can be assigned to accounts, roles, trips, and countries. This needs to be a many to many relationship because the same requirement could apply to multiple countries and/or trips and/or accounts etc.
I then need a table listing outstanding requirements for the user. For example: if a user has a certain account and there are requirements related to that account, then those requirements would be added to the user's list of requirements.
One solution I have is to first assign the requirements to the accounts, roles, trips, and countries using Pivot tables in a Many to Many relationship. Then using a polymorphic relationship I would connect the user to whichever pivot tables relate.
But I don't know how to do this or if it is even possible?
Here are my tables:
user_requirements
- id
- user_id
- requireable_id
- requireable_type
account_requirement
- id
- account_id
- requirement_id
role_requirement
- id
- role_id
- requirement_id
trip_requirement
- id
- account_id
- requirement_id
country_requirement
- id
- account_id
- requirement_id
Laravel 4.1 now has support for polymorphic many to many relationships.
Example below shows how I have implemented sharing Photos with both Products and Posts.
DB Schema
photos
id integer
filename string
alt string
photoable
id integer
photoable_id integer
photoable_type string
Models
Photo Model
class Photo extends Eloquent
{
public function products(){
return $this->morphedByMany('Product', 'photoable');
}
public function posts(){
return $this->morphedByMany('Post', 'photoable');
}
}
Product Model
class Product extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
Post Model
class Post extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
With the above, I can access all photos which are attached to a product as follows:
$product = Product::find($id);
$productPhotos = $product->photos()->all();
I can also iterate over to display all photos as any collection of models.
foreach ($productPhotos as $photo)
{
// Do stuff with $photo
}
The above can be replicated almost exactly to your requirements.
create a requirements table
create a requireable table
In Requirement model, declare all morphedByMany relationships
In Country, Trip, Role etc. declare morphToMany relationships
nb - I've typed this out freehand in S/O with no code editor, so there will probably be a typo, error or two - but concept remains the same.
A polymorphic relation in Laravel 4 is intended for single MODEL associations, therefore you cannot achieve what you are trying to build with this method. This is due to the fact that a pivot table doesn't represent a Model.