Laravel get data based on foreign key - php

So I have 2 tables, TABLE1 and TABLE2.
They are linked throug Eloquent:
TABLE1 has many TABLE2's, and TABLE2 has one TABLE 1.
They are linked with foreign keys as such:
in TABLE2 table1_id -> links to -> TABLE1 id.
How do I retrieve the entire table data or TABLE 2, + replace table1_id with a column of table1 (let's say by booktitle for example)?
Sorry for the abstraction, but this is the best way I can explain it? :D

The easiest way is to make use of Eloquent's eager loading and fetch all records from table2 and their corresponding record in table1.
This will do the trick:
$results = Table2::with('table1')->get();
foreach ($results as $table2record) {
echo $table2record->id; //access table2 data
echo $table2record->table1->booktitle; //access table1 data
}

You need to make the relationship in the models , for example if you have a "Category" and this has many "Products" you need to put this code in your model
public function products()
{
return $this->hasMany('App\Product', 'foreign_key_you_have');
}
and when you need to retrieve all products associated to that category in your view you need to call the function of model, for example
#foreach($category->products as $cp) // with $category->products you call all products associated to your foreign_key
<h1>{{$cp->price}}</h1>
#endforeach

Related

Laravel: How to subselect two columns from another table in a query

Say I have the following tables:
event_relationships
id
user_id
relationship
primary_event_id
secondary_event_id
events
id
user_id
name
color
In my user model, I have my relationship setup like:
$this->hasMany(EventRelationships::class, 'user_id');
And each event relationship belongs to one user.
How can I use Laravel Eloquent to get a list of all the event relationships, but also get each event's name and color? Matching on the primary_event_id and secondary_event_id.
Is this possible with one query?
In pure eloquent, in the laravel way, that would be :
$eventRelationships = EventRelationships::with('primaryEvent', 'secondaryEvent')->get();
foreach($eventRelationships as $eventRelationship){
$primary_event_name = $eventRelationship->primaryEvent->name;
$secondary_event_name = $eventRelationship->secondaryEvent->name;
}
but it's in 2 queries. If you want only one query, you have to use a join :
$eventRelationships = EventRelationships::query()
->join('events as primary_events', 'events.id', 'event_relationships.primary_event_id')
->join('events as secondary_events', 'events.id', 'event_relationships.secondary_event_id')
->select('event_relationships.*', 'primary_events.name as primary_event_name', 'secondary_events.name as secondary_event_name')
->get();
foreach($eventRelationships as $eventRelationship){
$primary_event_name = $eventRelationship->primary_event_name;
$secondary_event_name = $eventRelationship->secondary_event_name;
}
It might be easier to use the first one as you manipulate eloquent object

Laravel joins not working on 3 different tables

Model
Album::join('tracks', 'albums.track_id', '=', 'tracks.id')
->join('singers', 'tracks.singer_id', '=', 'singers.id')->get();
Snigers table
id - int
name - string
Tracks table
id -int
name - string
singers_id - JSON // example["1","2"]
Album table
id - int
name - string
tracks_id - JSON // example ["1","2"]
here first singers table after track table reference array of id multiple and next alums table reference track table id is also array.how to joins this three table
There's no need to use joins here, if you have a pivot table for these, here's what you can simply do:
In your models you can simply create a relation like this:
Album Model:
public function tracks() {
return $this->hasMany(Track::class);
}
public function singers() {
return $this->hasMany(Singer::class);
}
and then call it in your controller.
AlbumController.php
Album::where('id',1)->with('tracks','singers');
This will simply fetch all the records with Tracks and Singers that belong to Album id 1.

Laravel gather data by relational id

In my application, I have a posts table, categories tables and category_post table as a post and category have a many to many relationship.
I want to get all posts with their attached categories, but also group them together as on my frontend I want to be a loop over an object and show a list like this,
Cooking
Post Number 1
Post Number 3
Post Number 4
Music
Post Number 2
Post Number 5
Languages
Post Number 6
Post Number 7
I know in my controller I can do this,
$posts = Post::with('categories')->get();
But I don't how to groupBy a relational attribute or if I can structure the returned data in such a way that I can loop over it to form the list below.
you can get the data from db and then group them the way you want:
$posts = Post::with('categories')->get();
$result = $posts->groupBy([
'categories',
function ($item) {
return $item['category_name'];
},
], $preserveKeys = true);
more details about grouping by relation fields in:
https://laravel.com/docs/7.x/collections#method-groupby
As per given your table: posts and categories tables are the main tables and category_post table is a pivot table which contains the relation between posts and categories table :
So, Your relation should be posts->category_post->categories
$posts = Posts::with('category_post')->get();
$grouped = $posts->groupBy('category_post.category_id');
The category_post also related to the categories table for categories data.
In category model you cam setup and belongsToMany relation like the following
function posts()
{
return $this->beongsToMany(Post::class, 'category_post', 'category_id', 'post_id');
}
Then do as Arun A S suggested.

Duplicated records in Yii2 GridView

It was working just fine, but I had to import data afresh in the existing order1 table which is related to order_item table on order.id = order_item.order_id and order_item.location_id = location.id
So to get the location in GridView of order1 table I had relation defined like so:
public function getLocation() {
return $this->hasOne(Location::className(), ['id' => 'location_id'])->viaTable('{{%order_item}}', ['order_id' => 'id']);
}
Now I have multiple records in the GridView. The query formed for the GridView is like:
SELECT `order1`.*
FROM `order1`
LEFT JOIN `order_item` ON `order1`.`id` = `order_item`.`order_id`
LEFT JOIN `location` ON `order_item`.`location_id` = `location`.`id`
where 1 ORDER BY `id` DESC
LIMIT 20;
How I can fix this as inner join or otherwise, so that it returns records only once from order1 table?
In GridView I am using location.location_title.
Note: there are multiple order items per order.
also Tried:
public function getOrderItem()
{
return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}
public function getLocation()
{
return $this->hasOne(Location::className(), ['id' => 'location_id'])
->via('orderItem');
}
You need to add GROUP BY in your search model to ensure that orders will not be duplicated in query results:
$query->groupBy('order1.id');
Although hasOne() seems to be incorrect (if one order can have multiple items, then it could also have multiple locations), changing this to hasMany() will not fix GridView results. You need to be careful with one-to-many or many-to-many relations, usually you need to use GROUP BY to remove duplicates or adjust your DB structure or joins in search model, to avoid such situation.
BTW: Adding groupBy() in relation definition (getLocation()) is almost always incorrect. This is not a job of relation definition to handle grouping of main model results (you can be almost sure it will create issues with lazy loading).

How to write correct query to get not deleted rows?

I have users table and I use softDeletes() in my table. Also I have candidates table where have foreign key (user_id) to users table.
Generaly how I can get candidates which users is not deleted?
Here my code for get candidates with not deleted users:
$candidates = Candidate::all();
$activeCandidates = [];
foreach ($candidates as $candidate) {
if($candidate->user) {
$activeCandidates[] = $candidate;
}
}
Can be solved my problem without looping with subquery?
has() is to filter the selecting model based on a relationship. So, it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
$candidates = Candidate::has('user')->get();

Categories