laravel eloquent left join not outputting - laravel-4

I'm trying to achieve this
SELECT *
FROM pending
LEFT JOIN users ON pending.user_id = users.id
WHERE pending.school_id = '1'
Which produces two results of the two tables combined with the users details output.
Pending Model
public function users(){
return $this->belongsTo('User');
}
public function school(){
return $this->belongsTo('School');
}
User model
public function pending(){
return $this->hasMany('Pending','user_id');
}
School Model
public function pending(){
return $this->hasMany('Pending','school_id');
}
Controller
$pending_user = Pending::with('users')->where('school_id', '=', '1')->get();
This retrieves an array of the two records but a null result in the user array.
"users":null
Any help appreciated.

I have decided to go with this
$pending_user = Pending::select('first_name','last_name','user_id','how')->where('school_id', '=', '1')->leftjoin('users','pending.user_id','=','users.id')->get();

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();

Limiting laravel query using whereIn

So i have a query to make but i don`k know how best to it.
I have 2 class like below:
User.class
class User {
function posts(){
return $this->hasMany(Post::class, 'user_id');
}
}
Post.class
class Post {
function user(){
return $this->belongsTo(User::class, 'user_id');
}
}
and in my controller i want to get posts per User with a limit for each user NOT for all results. So here is what i have this in my controller:
function getPosts(Request $request){
$user_ids = [1,2,3,4];
$posts = Post::whereIn('user_id', $user_ids)->latest()->take(10)->get();
return $posts;
}
So the above get will get me just 10 entries from all of them yet i want to get 10 for each user nomatter how many user IDs
You can simply limit the relationship with a sub-query:
User::with(['posts' => function($query) {
return $query->limit(10);
}]);
May be something like
DB::table('posts as p1')->leftJoin('posts as p2', function($join){
$join->on('p1.id', '=', 'p2.id')
})->whereIn(p1.user_id, $user_ids)->groupBy('p1.id')->having(COUNT(*) < 10)->orderBy([id, created_at]);
will work for you. for the reference question
The query was
SELECT user_comments.* FROM user_comments
LEFT OUTER JOIN user_comments user_comments_2
ON user_comments.post_id = user_comments_2.post_id
AND user_comments.id < user_comments_2.id
where user_comments.post_id in (x,x,x)
GROUP BY user_comments.id
HAVING COUNT(*) < 3
ORDER BY user_id, created_at
Roughly in DB query builder, it will be like
DB::table('user_comments as uc1')->leftJoin('user_comments as uc2', function($join){
$join->on('uc1.post_id', '=', 'uc2.post_id')->andOn(uc1.id < uc2.id);
})->whereIn(uc1.post_id, [x,x,x])->groupBy('uc1.id')->having(COUNT(*) < 3)->orderBy([user_id, created_at]);
I hope this is helpful for you and give you good idea to get it.

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;

addGlobalScope withCount relationship's relationship

I have a 3 models: Phone, Product and Store.
A phone has many Product which belongs to a Store.
I am trying to add a golbal scope so that every time I load a phone, products and stores counts are loaded automatically.
products_count works fine, however stores_count is a bit tricky since store is not a Phone's relationship but a Product's.
I have tried the following but it gives me an error "Method getRelated does not exist.", I assume because stores() now returns a collection.
Any ideas as to how I could add the stores_count?
public static function boot(){
parent::boot();
static::addGlobalScope('products', function ($builder){
$builder->withCount('products');
$builder->withCount('stores'); <----- gives error
});
}
public function products(){
return $this->hasMany(Product::class);
}
public function stores(){
$store_ids = $this->products()->get(['store_id'])->unique();
return Store::find($store_ids);
}
Update after #Sandeesh answer.
I tried to use hasManyThrough but it returns an empty collection which is wrong.
When I dd($phone->products); I can see 7 products which have 3 different stores.
public function stores(){
return $this->hasManyThrough(Store::class, Product::class,
'store_id', 'id');
}
Database schema
Phone
-id
Product
-id
-phone_id
-product_id
-store_id
Store
-id
Update 2
So I managed to get the produced query from the stores() method above.
select `phones`.*,
(select count(*) from `products` where `phones`.`id` = `products`.`phone_id`) as `products_count`,
(select count(*) from `stores` inner join `products` on `products`.`id` = `stores`.`id` where `phones`.`id` = `products`.`store_id`) as `stores_count`
from `phones` where `slug` = ? limit 1
The problem is in the third line. The query is messed up, not sure what is wrong with the relationship though.
You can using hasManyThrough
https://laravel.com/docs/5.4/eloquent-relationships#has-many-through
public function stores()
{
return $this->hasManyThrough(Store::class, Product::class);
}
Edit
This should give you what you need. But eager loading is always better
protected $appends = [
'productCount',
'storeCount'
];
public function getProductCountAttribute()
{
return $this->products()->count();
}
public function getStoreCountAttribute()
{
return Store::whereIn('id', $this->products()->pluck('store_id')->toArray())->count();
}

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();
}

Resources