How to use where() for column that belong to with() - laravel

I'm working with Laravel framework.
I want to get the data for promotion with the certain category.
<b>Table</b><br>
product<br>
------<br>
id<br>
name<br>
price<br>
promotion<br>
----------<br>
id<br>
product_id<br>
discount<br>
category<br>
---------<br>
id<br>
name<br>
product_category<br>
----------------<br>
product_id<br>
category_id<br>
$promotions = Promotion::with('product')->with('category')
->whereIn('category_id', ['1','2'])
->paginate(9);
Promotion model - connect relation for product and category
// relationship with product
public function product()
{
return $this->belongsTo('App\Model\Product');
}
//relationship with category
public function category()
{
return $this->belongsToMany('App\Model\Category', 'products_categories', 'product_id', 'category_id');
}
Error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'category.id' in 'where clause' (SQL: select count(*) as aggregate from promotions where category.id in (1, 2))

Try this:
$promotions = Promotion::with('product.category')
->whereIn('category_id', ['1','2'])
->paginate(9);
Assuming that you have to create the correct relations in models.
Edit:
In the Promotion Model :
// relationship with product
public function product()
{
return $this->belongsTo('App\Model\Product');
}
and the Product Model:
//relationship with category
public function product_category()
{
return $this->belongsTo('App\Model\ProductCategory', 'product_id', 'id');
}
In the Category Model:
//relationship with category
public function product_category()
{
return $this->belongsToMany('App\Model\ProductCategory', 'category_id', 'id');
}
So the query like:
$promotions = Promotion::with('product.product_category')
->whereIn('category_id', ['1','2'])
->paginate(9)

How about :
$promotions = Promotion::with([ 'product.category' => function($q){
return $->whereIn('category_id', ['1','2']);
}])
->paginate(9);
If you want to get all promotions which have a category having id in 1,2 you can do :
$promotions = Promotion::whereHas('product.category' => function($q){
return $->whereIn('category_id', ['1','2']);
})
->paginate(9);
This will just get you promotions and not the categories. if thats what you were looking for.

You can simply use this:
$promotions = Promotion::whereHas(
'product.category',
function ($q) {
$q->whereIn('category_id', ['1', '2']);
})
->paginate(9);

Related

Laravel Order Collection Through Double Relationships

I am sending a Vehicle to my blade template which has a relationship of products that displays all the products fitting a vehicle.
Vehicle.php
public function products() {
return $this->belongsToMany(Product::class, 'vehicle_product');
}
I am strugging to figure out how to order those products based on a 3rd relationship's (product_group()) priority attribute.
Product.php
public function product_group() {
return $this->belongsTo(ProductGroup::class);
}
Blade Template
#foreach ($vehicle->products->orderBy('product_group.priority') as $product)
...
Use sortBy instead of orderBy but you must have products and product_group on 'vehicle' before applying it.
$vehicle = Post::query()
->with([
'products' => fn($q) => $q->with('product_group')
])
->where('id', 1)
->first();
$vehicle->products
->sortBy(fn($product) => $product->product_group->priority)
->values()
->all();

How to filter by date in Eloquent relationship

I've two tables first_levels and second_levels the first_levels have a relationship with themselves as parent and child and in the second table, I store the transactions.
my Model:
public function children()
{
return $this->hasMany(first_level::class, 'parent_id', 'Nominal')
->with(['children', 'transactions'])
->withsum('transactions', 'debit')
->withsum('transactions', 'credit');
}
public function transactions()
{
return $this->hasMany(second_level::class, 'first_level_id', 'id');
}
my controller:
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->get();
return response()->json(['data' => $items]);
}
using this model and controller I can get all the data from the first and second tables but when I want to filter the second table based on the created_at column I'm unable to do it.
I tried this method but it didn't work.
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->wherebetween('children.transactions.created_at', [$request->from, $request->to])
->get();
return response()->json(['data' => $items]);
}
I get this error
Column not found: 1054 Unknown column 'children.transactions.created_at' in 'where clause' (SQL: select * from `first_levels` where `parent_id` = 0 and `company_id` = 1 and `children`.`transactions`.`created_at` between 2022-01-10 and 2022-02-09)",
try
function getGeneralLedger(Request $request)
{
$items = first_level::with('children')
->where('parent_id', 0)
->where('company_id', $request->user()->company_id)
->whereHas('children.transactions', function ($q) use ($request) {
$q->wherebetween('created_at', [$request->from, $request->to]);
})
->get();
return response()->json(['data' => $items]);
}
Source: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

laravel eloquent with return only same column values

This is a little complex for me,so I decided to get some help.
Taxonomy has :
public function products()
{
return $this->belongsToMany(
Product::class,
'term_relationships',
'term_taxonomy_id',
'object_id'
);
}
And Product has :
public function taxonomies()
{
return $this->belongsToMany(
Taxonomy::class,
'term_relationships',
'object_id',
'term_taxonomy_id'
);
}
This will select all products with all its taxonomies where taxonomy starts with pa_.
\Corcel\WooCommerce\Model\ProductCategory::find(401)->products()->with(['taxonomies'=> function ($query) {
$query->where('taxonomy', 'like', "pa_%");
}])->get(['ID'])->makeHidden(['pivot']);
All I want is to select only taxonomies which all have the same taxonomy column value.
like they all have : taxonomy -> pa_shirt_size and taxonomy -> pa_shirt_color
Here's the sql output of eloquent :
select * from `wp_posts` inner join `wp_term_relationships` on `wp_posts`.`ID` = `wp_term_relationships`.`object_id`
where `post_type` = 'product' and `wp_term_relationships`.`term_taxonomy_id` = 401 and exists (select * from
`wp_term_taxonomy` inner join `wp_term_relationships` on `wp_term_taxonomy`.`term_taxonomy_id` =
`wp_term_relationships`.`term_taxonomy_id` where `wp_posts`.`ID` = `wp_term_relationships`.`object_id` and `taxonomy`
like 'pa_%')
So I think using something like :
group by `taxonomy` having count(*) = count(wp.posts.ID)
I can get the number of posts and if that is equal to taxonomy count it means we're good.
But how to access wp.posts.ID from the subquery in with function I couldn't find a way yet.
I suggest you get the products' count, then get all the taxonomies that have all the products count:
$Products_count = Product::count();
$sharedTaxomies = Taxonomy::has('products', '=', $Products_count)->get();
note: I suppoe the relation in Taxonomy called products not posts.
first: i think you mean products() instead posts() ?
public function products()
{
return $this->belongsToMany(
Product::class,
'term_relationships',
'term_taxonomy_id',
'object_id'
);
}
Secound: if you have access to products like:
$products = Product::all();
you can after iterate the $products and you have access to the taxonomies like:
print_r( $products[0]->taxonomies );

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!

Laravel 5: Count product by category where active product only

In Laravel 5.4, I have my relationship:
public function products()
{
return $this->hasMany(Product::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
And my query is:
$x = Category::with('products')->where('active', 1)->get();
It does show all category names correctly, but how to count only product 'active = 1'? I don't wish to count all products, but active products only.
try this:
$x = Category::with(['products' => function($query) { $query->where('active','=', 1); }])->where('active', 1)->get();
That will give you products that are active and then only categories where products are active.
Try this to be more specific. Additional from idea of #linuxartisan
$x = Category::whereHas('products', function ($query) {
$query->where('products.active', '=', 1);
})
->where('categories.active', '=', 1)
->get();
I am assuming you have active field for product as well as category.
Just try this query
$x = Category::whereHas('products', function ($query) {
$query->where('products.active', 1);
})->where('categories.active', 1)
->get();
public function products()
{
return $this->hasMany(Product::class)->where('active',1);
}
This is working in Laravel 7

Resources