How to fetch count from distant relationship in laravel way? - laravel

I am trying to fetch all the attributes with product count that is associated with products in the given category.
table structure
attributes table:
| id | name | value | filterable |
products table:
| id | name |
categories table:
| id | name |
attribute_product pivot table:
| id | attribute_id | product_id
category_product pivot table:
| id | category_id | product_id
Below is how my models look like.
Attribute
public function products(){
return $this->belongsToMany('App\Models\Product');
}
Product
public function attributes(){
return $this->belongsToMany('App\Models\Attribute');
}
public function categories(){
return $this->belongsToMany('App\Models\Category');
}
Category
public function products(){
return $this->belongsToMany('App\Models\Product');
}
I can get all the attributes associated with a product in the given category with the below query.
Attribute::where('filterable', '=', 1)
->whereHas('products.categories', function (Builder $query) use ($category) {
$query->where('category_product.category_id', '=', $category->id);
})->get();
However, I cannot figure out how I should get product counts.
I started testing query builder to achieve this but condition on where pivot seems to be binding attribute_product.attribute_id as a string value instead of the column value.
$data = DB::table('attributes')->where('filterable', '=', true)
->whereExists(function ($query) {
$query->select('*')->from('products')
->join('attribute_product', function ($join){
$join->on('products.id', '=', 'attribute_product.product_id');
})->where('attributes.id', '=', 'attribute_product.attribute_id');
})->get();
Below is more or less the final SQL query I need to send to the database
select `attributes`.*,
(SELECT
count(*) from `products`
inner join `attribute_product` on `products`.`id` = `attribute_product`.`product_id`
where `attributes`.`id` = `attribute_product`.`attribute_id`) as `products_count`
from `attributes` where `filterable` = 1
and EXISTS
(select * from `products` inner join `attribute_product` on `products`.`id` = `attribute_product`.`product_id`
where `attributes`.`id` = `attribute_product`.`attribute_id`
and EXISTS
(select * from `categories` inner join `category_product` on `categories`.`id` = `category_product`.`category_id`
where `products`.`id` = `category_product`.`product_id` and `category_product`.`category_id` = 9))
Please, someone, assist me in getting attributes with associated product count in the laravel way.

Check out the
withCount('relation_name')
method in eloquent Ex:
$posts = App\Post::withCount([
'comments',
'comments as pending_comments_count' => function (Builder $query) {
$query->where('approved', false);
}
])->get();

I managed to get all my results in a single request with the below query. Thanks! #athul for showing the direction.
Attribute::where('filterable', '=', 1)->whereHas('products.categories', function (Builder $query) use($category) {
$query->where('categories.id', '=', $category->id);
})
->withCount(['products' => function ($query) use($category) {
$query->whereHas('categories', function (Builder $query) use ($category) {
$query->where('categories.id', '=', $category->id);
});
}])->get();

Related

Order by relationship with pagination laravel eloquent

I have the relationship below, an application belongs to a user.
Users table
ID | Name
1 | Danny
2 | Mark
Applications table
ID | user_id
1 | 1
2 | 2
Application.php
public function user()
{
return $this->belongsTo(User::class);
}
I'm trying to sort the application by user's name and paginate the result. I tried the code below, the pagination is working but the order by doesn't have any effect.
$query = Application::query();
$query = $query->with(['user' => function ($query){
$query->orderBy('name', 'DESC');
}]);
$query = $query->paginate(10);
Try using inner join and order by relation column:
$applications = Application::select('*')
->join('authors', 'applications.user_id', '=', 'users.id')
->orderBy('authors.name', 'DESC')
->paginate(10);
Try this:
Application::join('users', 'applications.user_id', '=', 'users.id')
->orderBy('users.name','desc')
->with('users')
->get();

How to get post which have multiple table relationship?

my database scheema
Table POST
| id | title | content |
Table SharedGroup
|id | title | slug
Table Post_SharedGroup
|id| post_id | shared_group_id|
i want to make a query in laravel that i give slug of sharedgroup and get post of it
$data = Post::whereHas('sharedGroup',function($query) use($slug){
$query->whereIn('slug',$slug);
})->get();
where $slug is your slug array given by you
Model Post
public function sharedGroup(){
return $this->belongsToMany('App\SharedGroup');
}
Model SharedGroup
public function post(){
return $this->belongsToMany('App\Post');
}
You seem to just want a basic join between the three tables:
$posts = DB::table('POST p')
->join('Post_SharedGroup ps', 'p.id', '=', 'ps.post_id')
->join('SharedGroup s', 'ps.shared_group_id', '=', 's.id')
->whereIn('s.slug', array(1, 2, 3)) // match slug values (1, 2, 3)
->select('p.*')
->get();

Laravel: multiple where clauses in a many-to-many relationship

I am not able to create this sql query on laravel:
select * from `events_theatre` where
event_id IN (
select id from events where (`events`.`id` = `events_theatre`.`event_id` and `user_id` = 1 and `event_type` ='theatre') and `events`.`deleted_at` is null
)
or event_id IN (
select id from events inner join events_managers on events.id = events_managers.event_id and events_managers.user_id = 1
)
and `events_theatre`.`deleted_at` is null
The Events_Theatre model has this relationship:
public function event()
{
return $this->hasOne('App\MyEvent', 'id');
}
While the MyEvent model has this relationship:
public function managers()
{
return $this->belongsToMany('App\User', 'events_managers', 'event_id', 'user_id');
}
Pratically an Events_Theatre model is an Event model, and an Event model may have many managers but just 1 admin.
I need to get that Events_Theatre (and their MyEvent) whose user is an admin or one of the managers.
I tried with this eloquent query:
$list = App\Events_Theatre::whereIn('event_id', function ($query) {
$query
->where(['user_id' => Auth::id(), 'event_type' => 'theatre'])
->orWhereHas('managers', function ($query) {
$query->where('user_id', Auth::id());
});
});
But I get this sql query:
select * from `events_theatre` where
exists (
select * from `events` where (
`events`.`id` = `events_theatre`.`event_id` and `user_id` = 1 and `event_type` = 'theatre'
) or exists (
select * from `users` inner join `events_managers` on `users`.`id` = `events_managers`.`user_id` where `events_managers`.`event_id` = `events`.`id` and `user_id` = 1
)
and `events`.`deleted_at` is null
) and `events_theatre`.`deleted_at` is null
But its wrong. How can I solve this?
Thanks
UPDATED
I got the answer. This is the eloquent code I used:
$list = Events_Theatre::whereHas('event', function ($query) {
$query
->where(['user_id' => Auth::id(), 'event_type' => 'theatre']);
})->orWhereHas('event', function ($query) {
$query
->whereHas('managers', function ($query) {
$query->where('user_id', Auth::id());
});
})->get();
You can try has method
App\Events_Theatre::has('event')->orhas('managers')->get();

query with Laravel Eloquent ORM

How can I make this query in Laravel, using Eloquent ORM?
select * from posts p order by ( select count(*) from likes where flag = 'c' and p.id = post_id ) Desc limit 3
I have this relationship in my models
Post.php
public function likes(){
return $this->hasMany('Like', 'post_id');
}
Like.php
public function post(){
return $this->belongsTo('Post', 'post_id');
}
Thanks! :)
You may try something like this:
$posts = Post::leftJoin('likes', function($join) {
$join->on('posts.id', '=', 'likes.post_id')->where('flag', '=', 'c');
})
->select('posts.*', 'likes.post_id', DB::raw('count(likes.post_id) as pCount'))
->groupBy('post_id')
->orderBy('pCount', 'desc')
->take(3)
->get();

Laravel Relationships with 3 tables and two pivot tables

Hi I used Laravel relationships with many to many pivot tables without problems but i can't get around the logic i need to write to create a relation between 3 models using 2 pivot tables to execute a query like the one below:
select * from product
left join product_to_category on product_to_category.product_id = product.product_id
left join category on product_to_category.category_id = category.category_id
left join category_to_brand on category_to_brand.category_id = category.category_id
left join brand on brand.brand_id = category_to_brand.brand_id
where brand.key = 'furniture-hire-uk'
and category.slug = 'chair-hire'
the table structure is as follows:
product
product id
some more feilds
category
category id
some more feilds
brand
brand_id
key
some more feilds
product_to_category
product_id
category_id
category_to_brand
category_id
brand_id
Using relationships:
// assuming relations:
categories: Product belongsToMany Category
brands: Category belongsToMany Brand
// and tables according to your question:
product, category, brand
$slug = 'chair-hire';
$key = 'furniture-hire-uk';
Product::whereHas('categories', function ($q) use ($slug, $key) {
$q->where('category.slug', $slug)
->whereHas('brands', function ($q) use ($key) {
$q->where('brand.key', $key);
});
})->get();
Or manual joins:
Product::join('product_to_category as pc', 'product.id', '=', 'pc.product_id')
->join('category', function ($j) use ($slug) {
$j->on('category.id', '=', 'pc.category_id')
->where('category.slug', '=', $slug);
})
->join('category_to_brand as cb', 'category.id', '=', 'cb.category_id')
->join('brand', function ($j) use ($key) {
$j->on('brand.id', '=', 'cb.brand_id')
->where('brand.key', '=', $key);
})
->get(['product.*'])

Resources