Reputation: 858
I have a Product
which has multiple Variants
.
I want to select all Products and sort them based on the price of first underlying variant child.
Product A
Product B
Product C
In this case if i want to order on price asc
i expect to get the following result ordering:
My current (not working) query:
Product::with(['variants' => function ($q) {
$q->orderBy('price', 'desc');
}])->orderBy('variants.price', 'desc')->get();
Upvotes: 4
Views: 2989
Reputation: 411
You can not order by when using with()
:
Because with()
will make two separate queries like this:
SELECT * FROM users;
SELECT * FROM roles WHERE id IN (1, 2, 3, 4, whatever...);
The solution for your problem is use join()
so you make only one query:
$order = 'desc';
$products = Product::join('variants', 'variants.product_id', '=', 'products.id')
->orderBy('products. price', $order)
->select('products.*')
->paginate(10);
Upvotes: 2
Reputation: 858
Solved it by using the following query:
Product::join('variants', function ($join) {
$join->on('variants.product_id', '=', 'products.id');
})
->select('products.*', DB::raw("MAX(variants.price) as max_variant_price"))
->groupBy('variants.product_id')
->orderBy('max_variant_price')
->get();
Upvotes: 1
Reputation: 4499
You can Order them after the fetch.
$products = Product::with('variants')
->get()
->sortBy(function($product) {
// if you want to order by first found
return $product->variants->first()->price;
// if you want to order by max price
return $product->variants->max->price;
// or min price
return $product->variants->min->price;
// or average price
return $product->variants->average->price;
});
Upvotes: 0