Reputation: 31
I am trying to count all active products in parent category. A parent category has many child categories(only one level deep). A product can be assigned to multiple child categories but not parent category.
For ex. I have "Toys"(parent) category having 3 child categories "for boys"(having 5 products), "for girls" (having 6 products), "for teens" (having 12 products).
My sidebar menu at homepage have all the parent categories and wants to show product count of respective parent category using eloquent way. The eloquent query is being used in view composer.
Using above example, I want to show like:
Toys 23 (5 + 6 + 12 = 23 after totaling products from child categories)
Games 10
Sports 15
and so on..
I want to get parent category with product count, and not child categories details.
My Category.php Model
public function parent() {
return $this->belongsTo(self::class, 'parent_id');
}
public function children() {
return $this->hasMany(self::class, 'parent_id', 'id');
}
public function products() {
return $this->belongsToMany('App\Product');
}
My Product.php Model
public function categories() {
return $this->belongsToMany('App\Category');
}
public function user() {
return $this->belongsTo('App\User');
}
Queries I have tried
Category::select('id', 'parent_id', 'slug' ,'name')->where(['active' => 1, 'parent_id' => null])->with(['children' => function($query) {
$query->withCount('products');
}])->get();
This give me product count of children. I can loop through children and can add total product for parents. But, doesn't seems me a good way, since this loads child categories data too which I don't need. I have a total of around 400 categories.
Category::select('id', 'parent_id', 'slug' ,'name')->where(['active' => 1, 'parent_id' => null])->with('children')->withCount('products')->get();
This gives product count as 0, obviously as parent category has no product assigned to it.
I see a lot of examples her using withCount, but they all explains hasManyThrough relations. I am having belongsToMany relation set up in Category and Product Model. Guide me if withCount is implemented in belongsToMany relation anywhere.
I am looking for optimized database queries to get the result I need. Please let me know your thought.
Thanks a lot for your valuable time.
Upvotes: 3
Views: 1293
Reputation: 1
add extra columns in the category view table. Total Product Count Total Categories Count instead of adding count on exisisting one its the idle way you can achieve the goal in an hour or two
Upvotes: -1
Reputation: 13394
Add a column to this categories
table, like product_sum
. So you just maintain this field when you create or update the category
or product
.
Cache categories to reduce query times, like this:
Cache::remember($cache_key, $ttl, function () {
return Category::select('id', 'parent_id', 'slug' ,'name', 'product_sum')
->where(['active' => 1, 'parent_id' => null])
->get();
});
And remember every time you change the product_sum, you need to clear this cache key.
Upvotes: 1
Reputation: 151
If I understand your question correctly you can achieve this by adding a method to your category model. Like this
// Category.php
public function getProductCountAttribute()
{
return Product::whereIn(
'category_id',
Category::where('parent_id', $this->getKey())->pluck('id');
)
}
This will get all the id's from the categories that have the current category as a parent. Then use the id's to get all the products that are part of the child categories and count them.
The method above is an Accessor so you can call it on the toys category like $toyCategory->product_count
Hopefully, this answers your question & sends you in the right direction.
Sidenote: This will generate a query per category this is not the ideal way but it is better than generate a query for every category child.
Upvotes: 1