Laravel fetch intermediate table data with many to many relationship - laravel

I have 3 tables
user, specialities & results
results contain specialitie_id, user_id
I have create many-to-many relationship
Here's the relationship in user model
public function specialities()
{
return $this->belongsToMany(Speciality::class, 'results', 'user_id', 'specialitie_id')->withPivot('result', 'color');
}
I want to fetch data from the result table based on specialitie_id
If my url is
abc.com/result/5
I have attached table structure as well,
it should show me result related to specialitie_id 5
I tried this but it doesn't work
$result = User::with('specialities')->where('id', 5)->get();
Any help would be appreciated.

Your current query:
$result = User::with('specialities')->where('id', 5)->get();
Is saying, give me all results where the USER_ID = 5 WITH all the specialities related to it.
You are very close but did it backwards:
//Give me all results where the SPECIALITY_ID = 5
//WITH all the users related to it
$result = Speciality::with('users')->where('id', 5)->get();
Please note that the above is an array
Example of a Controller Function:
public function results($id){
$results = Speciality::with('users')->where('id', $id)->get();
return view('user_specialities', compact('results'));
}
Example view user_specialities:
#foreach($results as $result)
<p>Result: {{$result->result}}</p>
<p>Formulary: {{$result->formulary}}</p>
<p>Color: {{$result->color}}</p>
<p>User ID: {{$result->user->id}}</p>
<p>User Name: {{$result->user->name}}</p>
#endforeach
Speciality Model:
public function users()
{
return $this->belongsToMany(User::class, 'results', 'specialitie_id', 'user_id')->withPivot('result', 'color');
}
User Model:
public function specialities()
{
return $this->belongsToMany(Speciality::class, 'results', 'user_id', 'specialitie_id')->withPivot('result', 'color');
}

Related

Laravel: How to get data from 3 tables with relationship

I have 3 Tables:
Customers
id
name
Sales
customer_id
sale_date
Contacts
customer_id
contact_date
There aren't any update operations in the contacts table. Each process opens a new record in the contacts table. So, a user can have more than one records in the contacts table.
Here are my relations in models:
Customer
public function contacts()
{
return $this->hasMany(Contact::class);
}
public function sales()
{
return $this->hasMany(Sale::class);
}
Contact
public function customer()
{
return $this->belongsTo('App\Customer', 'customer_id');
}
Sale
public function customer()
{
return $this->belongsTo('App\Customer');
}
I would like to have the latest record of the contacts table and make it join with the other related tables.
Here is the query which I have tried:
$record = Contact::groupBy('customer_id')
->select(DB::raw('max(id)'));
$result = Customer::query();
$result->where('is_active', 'YES');
$result->with('sales');
$result->whereHas('contacts', function ($q) use($record){
return $q->whereIn('id', $record)->where('result', 'UNCALLED');
});
return $result->get();
In the blade file, I get some result in foreach loops. However, I am unable to get the related data from the sales and contacts table.
#foreach($result as $item)
#foreach($item->sales as $sale) // Has no output and gives error: Invalid argument supplied for foreach()
#foreach($item->contacts as $contact) // Has no output and gives error: Invalid argument supplied for foreach()
Can anyone help me how to display the sale and contact date? Or any idea for how to improve this code quality?
If you want the latest record of the contacts you can declare another relationship on the Customer model, e.g.:
public function latest_contact()
{
return $this->hasOne(Contact::class)->latest('contact_date');
}
BTW you can always declare one or more hasOne additional relationship if you have a hasMany in place the foreign key used is the same.
In this way you can retrieve latest_contact eager loaded with your Customer model:
$customer = Customer::with('latest_contact')->find($id);
Or use this relationship in your queries, something like that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->whereHas('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
Or that:
$customers = Customer::where('is_active', 'YES')
->with('sales')
->with('contacts')
->with('last_contact', function ($q){
return $q->where('result', 'UNCALLED');
})->get();
If you want you can declare last_contact with the additional where:
public function latest_contact()
{
return $this->hasOne(Contact::class)
->where('result', 'UNCALLED')
->latest('contact_date');
}
This way all other queries should be easier.
I hope this can help you.
I'm not sure, but can you try to do the following:
return Customer::where('is_active', 'YES')
->with([
'sale',
'contact' => function ($query) use($record) {
return $query->whereIn('id', $record)->where('result', 'UNCALLED');
}
])->get();

Error : Method Illuminate\Database\Eloquent\Collection::StudentInfo does not exist. (Laravel 5.6)

I am new to make join tables with Eloquent. I want to join 3 tables. But it shows me error. What's my mistake, if anyone notice it will be helpful for me. Here is tables....
In 1st table Applications(id,u_id,program_name) 2nd table StudentInfos(id,u_id,.....) 3rd table users(id,.....)
in Application model
public function StudentInfo()
{
return $this->hasOne('App\StudentInfo', 'u_id', 'u_id');
}
in StudentInfo model
public function User()
{
return $this->hasOne('App\user', 'u_id', 'id');
}
From controller
public function view_application($id)
{
$vu_data = Application::where('id', $id)->get();
$vu_data2 = $vu_data->StudentInfo()->get();
return $vu_data2;
}
$vu_data2 = $vu_data->StudentInfo()->get();
is returning a collection and not just a single Application Model. Change "get()" to "first()", and this will fix your first error. So change:
$vu_data = Application::where('id', $id)->get();
to
$vu_data = Application::where('id', $id)->first();
When you do get(), it returns a collection. You can do :
$vu_data = Application::findOrFail($id);
$student = $vu_data->StudentInfo;
$user = $student->User;

How to get top 10 category list in laravel eloquent query

i have three table one is category table and another is product table and one more product_to_category table, and it has only product_id and category_id column.
Now i want to get top 10 categories with maximum number of product, with details of 10 products from each category.
What i wrote is
$result = ProductToCategory::groupBy('category_id')->with(['product',function($q){
$q->take(10);
}])->orderBy('category_id)->take(10);
But this is not working.How to write this query properly
Can anyone please help. ty
Model relations
For Product model
public function category(){
return $this->belongsTo(ProductToCategory::class);
}
For Category model
public function products()
{
return $this->hasMany(ProductToCategory::class);
}
For ProductToCategory model
public function product()
{
return $this->hasMany(Product::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
The most efficient way would be using a raw SQL query because you can't filter products by using eager loading constraint.
But if you want an Eloquent solution anyway, define the relationships:
In the Product model:
public function categories()
{
return $this->belongsToMany(Category::class, 'product_to_category');
}
And in the Category model:
public function products()
{
return $this->belongsToMany(Product::class, 'product_to_category');
}
Then you'll have two options, both have their pros and cons:
1. This code will execute just 2 queries but will use more memory. You could get top ten categories with their products:
$categories = Category::withCount('products')->latest('products_count')->take(10)->with('products')->get();
And then keep only first ten products:
$categories->transform(function($category) {
$topProducts = $category->products->take(10);
unset($category->products);
$category->products = $topProducts;
return $category;
});
2. This solution will create 12 queries but will save the memory:
$categories = Category::withCount('products')->latest('products_count')->take(10)->get();
$categories->transform(function($category) {
$category->products = Product::whereHas('categories', function($q) use($category) {
$q->where('id', $category->id);
})
->take(10)
->get();
return $category;
});
Here is the DB facade version:
$tenPopularTags = DB::table('product_to_category')
->join('category', 'product_to_category.category_id', '=', 'category.id')
->select(DB::raw('count(product_to_category.category_id) as repetition, question_tag.tag_id'))
->groupBy('product_to_category.category_id')
->orderBy('repetition', 'desc')->take(10)
->get();
However I like #Alexey Mezenin way of doing it. Because that is the cleaner way have customized it a bit:
$tenCategories = Category::withCount('products')->orderBy('questions_count', 'DESC')->take(10)->get();
Have used both in my project blog with post and categories relationship and it works!

How to count average value for each user?

I have two tables: users, comments.
Each user has some comments.
I do request like as:
$users = User:with('comments')->get();
How can I count the average value in field comments.rate where users.id = comments.user_id
In result I should get collection with all rows wityh user information and field avg_rate
I tried to use ->avg(), but it returns only one row, not for each
I have own solution, but I have desire to move this code in model:
{{$users->reviewsAverage()->first()->avg("rate")}}
Model:
public function reviewsAverage()
{
return $this->hasMany('App\Review', 'user_id', 'id'); //->first()->avg('rate');
}
Have two functions one for the relationship and he other for the average function
public function comments()
{
return $this->hasManyThrough('App\Comment', 'id');
}
public function averageRating()
{
return $this->comments()->selectRaw('avg(rate) as average_rate, comment_id')
->groupBy('comment_id');
}
Then go ahead and query like this
foreach($users as $user){
$rate = $user->averageRate();
}

How get rows from closest table using one to one?

I have two tables:
Hotels | Countries
country id name
I need to get all notes from Hotels , and get Hotels.country will be name of country: Countries.name
There is function in Hotel model:
public function country()
{
return $this->hasOne('App\Country', 'country', 'id');
}
In controller I try to get all hotels with related countries:
$hotels = Hotel::all();
After I try to get country name for each row from $hotels:
foreach($hotels as $item){
echo $item->country["name"]; // It does not work
}
It should be
public function country()
{
return $this->belongsTo('App\Country', 'country', 'id');
}
After that,
#foreach ($hotels as $hotel) {{ $hotel->country->name }}
should work.
You will need to use eager loading.
$hotels = Hotel::with('country')->get();
Check out the documentation here.
In order to access the country name, it's a normal object:
$hotel->country->first()->name
If you want to have a direct function, in your Hotel Model
Hotel.php
public function countryName()
{
return $this->country->first()->name
}

Resources