confusion over which relationship to use in models for these two tables - sql

I have a user table that consists of these columns:
| id | username | password | email | pants_size_id | shirt_size_id |
pants_size_id and shirt_size_id are filled with foreign tables id keys where I store a list of sizes for pants and shirts in different country specific measures, example of pants_size table:
| id | UK_sizing | US_sizing | IT_sizing |
a single user will have only one pants and shirt size so the user table is filled with the ID of the corresponding rows in the size tables.
what kind of relationship does this imply between the user model and the pants and shirt sizing models?
Also how can I retrieve the data inside the foreign table column (example IT_sizing) when returning auth user return \Auth::user(); instead of the numeric size_id ?
In other words how can I retrieve say '32' (a pants size) instead of the pants_size_id (let's say '1').

Cato has the right answer, I can't exactly respond to it because of my rep but the logic in your other answer doesn't make sense from a relational standpoint.
Users don't belong to a size, instead, Users have a size.
To me it sounds like you mixed up the foreign and local key assignment it should be User->hasOne(pants_size).
In your model it would be the following, the explicitness of the keys isn't great, but if you have some weird thing laravel can't figure out this should work.
public function pants_size(){
return $this->hasOne('App\Pants_size','id','pants_size_id');
}
public function shirt_size(){
return $this->hasOne('App\Shirt_size','id','shirt_size_id');
}
To answer the other question of how to find the size (32), since you're dealing with three different measurements you have to have a where clause on the specific measurement the 32 represents, and get the id. If you specifically wanted the users you would call the eloquent query as so:
\Auth::User()->pants_size()->(..whatever measurement you want..)

Create a function establishing a hasOne relationship for both pants_size and shirt_size in the user model. Be sure to set the foreign key and local key correctly if you don't want Laravel to assume default keys (see here for details).
Once the functions are created, you will be able to obtain data about the user's size information like so: App\Model\User::find(123)->pants_size->UK_sizing. (This example is for a user with ID of 123).

this is how I made it work:
in USER model:
public function pants_size(){
return $this->belongsTo('App\Pants_size');
}
public function shirt_size(){
return $this->belongsTo('App\Shirt_size');
}
In Pants_size and Shirt_size Models:
public function user(){
return $this->hasMany('App\User');
}
That last one works also with hasOne.
The code I use to retrieve the data is:
public function index()
{
echo $user = User::find($id);
echo $pants = User::find($id)->pants_size->it_sizing;
echo $shirt = User::find($id)->shirt_size->it_sizing;
}

Related

Problem with making complex query in Eloquent

I have to make a query in which I should determine if product (wine) belongs to either white wine or red wine type, but here is the catch - table wine has only variety_id and variety table has type_id(red or white). I suppose that I should do it with a subquery but I just can't figure out how with Eloquent methods. Three tables are connected this way: wine can have only one variety and one variety can have multiple wines, one variety can have only one type, while one type can have multiple varieties. How could I check if a wine belongs to either type as that's one of the filters (along with product label, availability and so forth)?
Edit: I tried this but unsuccessfully:
$wines->whereHas('variety.type',function($query){
$query->where('id','=',1);
})->get();
Explanation: I know that id of the red type in Type table is 1 and by this I wanted to get all the red wines
If you have the following relationsips:
In model Wine:
public function variety()
{
return $this->belongsTo(Variety::class);
}
and in model Variety:
public function type()
{
return $this->belongsTo(Type::class);
}
you can get what you need with:
$colors = ['red', 'white'];
$redAndWhiteWines = Wine::whereHas('variety.type', function ($query) use ($colors) {
$query->whereIn('name', $typeNames);
})->get();
This is considering you have in your types table column name that has the actual color of the wine.

Django: Annotate table with field across a M2M mapping to another table

I want to get competition.name from a list of submissions.
In my setup, competitions and teams share a M2M relationship (with an associated competition-team object. Each competition-team pair can submit any number of submissions. I now have a dashboard page which I am trying to create a table of all submissions by the team accompanied by the respective competition's name. The output should look like:
| Submission Name | Submission Date etc. | Competition Name |
| Sub01 | 2020-12-30 2000 | Competition01 |
I have trouble retrieving the competition name from the submissions. Here are my models:
class Competition(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=30)
class CompetitionTeam(models.Model):
competition_id = models.ForeignKey('Competition', on_delete=models.CASCADE, to_field='id', db_column='competition_id')
team_id = models.ForeignKey('Team', on_delete=models.CASCADE, to_field='id', null=True, db_column='team_id')
class CompetitionSubmission(models.Model):
competitionteam_id = models.ForeignKey(CompetitionTeam, on_delete=models.CASCADE, db_column='competitionteam_id')
I wish to annotate a set of submissions with their respective competition names. I tried with:
submissions.annotate(competition_name=Subquery(Competition.objects.filter(id=Subquery(CompetitionTeam.objects.get(id=OuterRef('competitionteam_id')).competition_id)).values('name')))
"ValueError: This queryset contains a reference to an outer query and may only be used in a subquery."
I also tested with the following command:
CompetitionSubmission.objects.prefetch_related('competitionteam_id__competition_id')
It runs but the command seems to do nothing. I will update this post with other methods I try.
Thank you.
EDIT
submissions.annotate(competition_name=Subquery(Competition.objects.filter(id=Subquery(CompetitionTeam.objects.filter(id=OuterRef(OuterRef('competitionteam_id_id'))).values('competition_id'))).values('name')))
Seems to work correctly.
You can traverse ForeignKeys directly using double underscores.
CompetitionSubmission.objects.values(
'competitionteam_id',
'competitionteam_id__competition_id',
'competitionteam_id__competition_id__name',
'competitionteam_id__team_id',
'competitionteam_id__team_id__name',
)
This will only produce a single database query. Django ORM takes care of everything.
P.S. I would avoid using '_id' in field names as Django model fields are supposed to be referring to related objects themselves. Django automatically adds extra attributes with '_id' that contains the related object's id. Please see https://docs.djangoproject.com/en/3.1/ref/models/fields/#database-representation

Assign Null (missing) values on section access reduction

Suppose I have the following very simple data warehouse:
section application;
car:
LOAD * INLINE
[
CAR,USER
GETZ,George
];
person:
LOAD * INLINE
[
USER
George
Maria
];
As you can see, USER George has a CAR GETZ, while USER Maria has no car.
Is it possible to set the section access up, using reduction field=CAR, so that
a user can only see Maria, who has a null value on CAR?
I have read COUNTLESS posts. Many say to put an empty string- that doesn't work. I have also seen multiple "Answers" having sample qvds attached - and most of them use a single table with an empty string value to make the test, which then seems to work with the empty string value at section access. Of course, this is not the case I'm interested, as the empty string value is still different than a missing/nulul value
Because section access works via associations in Qlik it wouldn't be possible with your current data model. Maria doesn't have a null car - she has no car association (which will show as a null if you put USER and CAR in a table but it's a subtle difference). If structured your data a little differently you could potentially make it work with a blank... something like
car:
LOAD * INLINE
[
CAR,USER
GETZ,George
];
outer join(car):
LOAD * INLINE
[
USER
George
Maria
];
You might need to populate the null values with blank afterwards...
car2:
NOCONCATENATE LOAD
if(isnull(CAR),'',CAR) as CAR,
USER
Resident car;
drop table car;
If it's not possible to join the two tables then you could add blank entries to your car table?
car:
LOAD
*,
USER as USER2
INLINE
[
CAR,USER
GETZ,George
];
person:
LOAD * INLINE
[
USER
George
Maria
];
concatenate(car)
LOAD
USER,
'' as CAR
RESIDENT person
WHERE NOT EXISTS (USER2,USER);
There are also options with some kind of combined key or applymaps potentially, but hopefully one of the above is helpful enough...

SQL Join tables on different column types

I have two tables:
dbo.Dashboards
Id (int PK) Title(nvarchar) WidgetIds(nvarchar)
1 Test [1,2]
dbo.Widgets
Id (int PK) Details(nvarchar)
1 {'text': 'some data'}
2 {'text': 'test'}
Expected output:
Dashboard.Id Dashboard.Title Widget.Id Widget.Details
1 Test 1 {'text': 'some data'}
1 Test 2 {'text': 'test'}
I would like to get dashboards with assigned widgets by using Entity Framework.
My first solution is to get dbo.Dashboards and then dbo.Widgets. After that I can merge it in a backend, but it is not the best practice.
Is there any option to get Dashboards with assigned Widget list?
Function Include() is not working because there isn't FK relationship between tables.
It seems to me that you have a many-to-many relationship between Dashboards and Widgets: Every Dashboard has zero or more Widgets and every Widget is used by zero or more Dashboards.
In a proper database you would have a separate junction table. Apparently you chose not to use this pattern, but create a string that contains a textual representation of the widgets that a 'Dashboard` has.
If you plan to create a serious application I strongly advise you to
use the standard pattern in many-to-many relationships
If you don't, all your queries will be more difficult. Imagine the problems you'll experience if you want to delete a Widget. You'd have to check the textual representation of every Dashboard to check if the widget that you want to remove is used somewhere and change it.
If you want to configure your many-to-many relations ship according to the Entity Framework Code-First Conventions, you will have something like this:
class Dashboard
{
public int Id {get; set;}
public string Title {get; set;}
// every Dashboard has zero or more Widgets
public virtual ICollection<Widget> Widgets {get; set;}
... // other properties
}
class Widget
{
public int Id {get; set;}
// every Widget is used in zero or more Dashboards
public virtual ICollection<Dashboard> Dashboards{get; set;}
... // other widget properties
}
class MyDbContext : DbContext
{
public DbSet<Dashboard> Dashboards {get; set;}
public DbSet<Widget> Widgets {get; set;}
}
Because you stuck to the conventions, this is all that entity framework needs to know to understand that you want to configure a many-to-many relationship between Dashboards and Widgets. Entity Framework will create the junction table for you. It will automatically update this table whenever you add a Widget to a Dashboard. It will also create the proper joins whenever you want to fetch Dashboards with their Widgets, or Widgets with the Dasheboards that use them.
Your query will be fairly simple:
var DashBoardsWithTheirWidgets = myDbcontext.Dashboards
// I only want to see the super dashboards
.Where(dashboard => dashboard.Type = DashboardType.Super)
.Select(dashboard => new
{
// Select only the properties you plan to use:
Id = dashboard.Id,
Title = dashboard.Title,
// select only the Widgets you plan to use:
Widgets = dashboard.Widgets
.Where(widget => widget.Price > 100.00)
.Select(widget => new
{
// again select only the properties you plan to use
Name = widget.Name,
Price = widget.Price,
})
.ToList();
});
See how easy it is if you stick to the conventions?
If you really want your obscure method of using foreign keys, you need a function to remove the square brackets and the commas from the widgetIds, split the string into sub-strings, Parse them to numbers, and do a join.
But before you plan to continue on this path, experiment on how to add a Widget and a Dashboard. How to add a Widget to a Dashboard, how to remove a Widget. I think the time needed to reform your database into proper format is much less than the time you'll need to implement those functions
Solution 1:
You need to restructure the dbo.dashboards table. Change the column layout of dbo.dashboards to
Auto_Generated_ID, Unique_Identifier(PK), Title, WidgetIds
I know the above column restructuring is done in a bad way. But still this will work in your case.
After redesigning it you can use join between dbo.dashboards and dbo.widgets to retrieve it in an efficient way.
Solution 2:
The below-normalized tables will work in your case
dbo.dashboard
id, title (columns)
dbo.dashboard_widget
id, dashboard_id, widget_id (columns)
dbo.widgets
id, details (columns)
Query:
select d.id, d.title, dw.widget_ids, w. details from dbo.dashboard d INNER JOIN dbo.dashboard_widget dw ON d.id = dw.dashboard_id INNER JOIN dbo.widgets w ON dw.widget_id = w.id where d.id = << id number >>

REST APIs: Using Ids versus Actual Values in POST/PUT/GET

I am in a process of designing APIs to allow customers to manage their data using POST/PUT/GET.
One of the challenges for the API is that there are number of fields in entities that should have values from predetermined sets.
One of the approaches I see is to allow clients to pass IDs for each of the data filed(properties) and have a supplementary method to provide clients with available options for the data fields.
So the client interaction with the service will be:
Client: GET \Options (returns set of available options for each field)
Client: POST \Data (sends the DTO with set of IDs for each property this saves the data to the server)
Another option as I see is to let client to send actual values instead of IDs.
What approach do you recommend? And why?
Let clients pass the data as values BUT store the data as a foreign key on your server.
Let's say you design an API for adding cars and the car colour should be a value from a predetermined set.
HTTP requests:
GET cars/1
=> 200 OK
{ id: 1, name: "Ferrari", colour: "Red }
POST cars
{ name: Lamborghini, colour: "Blue" }
=> 201 Created (cars/2)
Database (just an example):
Table [Car]: #ID (Integer) , Name (Varchar) , ColourID (Integer)
Table [Colour] : #ID (Integer), Name(Varchar)
...where the Car.ColourID is a foreign key to your Colour.ID
The advantages are:
The API is easy to use
You still maintain the data constraint from predetermined sets, for example POSTing a car with colour: "Dog" should result in HTTP response with error information (e.g. Invalid colour).