When Laravel seeks to load relations, he will execute two requests similar to this:
SELECT * FROM products WHERE 1; SELECT * FROM prices WHERE product_id = 1;
What you want to do is add a condition to the second query to get a row with the most recent price. So, you would like something like this:
SELECT * FROM products WHERE 1; SELECT * FROM prices WHERE product_id = 1 ORDER BY price;
Fortunately, in Laravel Eager Load Constraints you can instead of passing a string to with() , you can pass an array with the name of the relationship as a key and closing the subquery as its value. Like this:
$products = Product::with(array('prices' => function($query) { $query->orderBy('created_at', 'desc'); }))->get();
Then in the code you can:
$product->prices->first();
to get the latest price of each product.
Note. You may notice that Laravel will still download all prices for each product. I donβt think there is a way around it while still using purely Eloquent, because working with impatience loads all relationship records in one request, so there is no easy way to say to get only the latest price for each product.
Another solution:
However, if you strictly need to know only the value from another table, you can make a sub-selection:
$products = Product::select('*') ->addSelect(DB::raw('(SELECT price FROM prices WHERE products.id = prices.product_id ORDER BY created_at DESC LIMIT 1) price')) ->get();
Unnawut
source share