Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting just the latest value on a joined table with Eloquent

I have two tables like this:

products:

+----+-----------+
| id |   name    |
+----+-----------+
|  1 | Product 1 |
|  2 | Product 2 |
|  3 | Product 3 |
|  4 | Product 4 |
+----+-----------+

prices:

+----+-------+------------+---------------------+
| id | price | product_id |     created_at      |
+----+-------+------------+---------------------+
|  1 |    20 |          1 | 2014-06-21 16:00:00 |
|  2 |    10 |          1 | 2014-06-21 17:00:00 |
|  3 |    50 |          2 | 2014-06-21 18:00:00 |
|  4 |    40 |          2 | 2014-06-21 19:00:00 |
+----+-------+------------+---------------------+

I have this relationship on Product:

public function prices()
{
    return $this->hasMany('Price');
}

I can easily run Product::with('prices')->get(); to get each product with each of the prices it's had.

How can I use Eloquent to only get the most recent price? (Also, what if I wanted the cheapest/most expensive price instead?)

like image 941
Rich Bradshaw Avatar asked Jun 21 '14 16:06

Rich Bradshaw


People also ask

What is latest () in Laravel?

latest() function in Laravel used to get latest records from database using default column created_at . latest() is the equivalent to orderBy('created_at', 'desc')

How can I get last ID in Laravel?

Using getPDO() Method You can also use the PDO Object to get the last inserted id of a table in Laravel. Firstly you will have to insert the record and right after that, you can call the lastInsertId() method on the PDO object.


1 Answers

You can tweak your relations to get what you want. Accepted answer of course works, however it might be memory overkill with lots of data.

Find out more here and there.

Here's how to use Eloquent for this:

// Product model
public function latestPrice()
{
   return $this->hasOne('Price')->latest();
}

// now we're fetching only single row, thus create single object, per product:
$products = Product::with('latestPrice')->get();
$products->first()->latestPrice; // Price model

That's nice, but there's more. Imagine you'd like to load highest price (just a value) for all the products:

public function highestPrice()
{
   return $this->hasOne('Price')
      ->selectRaw('product_id, max(price) as aggregate')
      ->groupBy('product_id');
}

Not very convenient yet:

$products = Product::with('highestPrice')->get();
$products->first()->highestPrice; // Price model, but only with 2 properties
$products->first()->highestPrice->aggregate; // highest price we need

So add this accessor to make the life easier:

public function getHighestPriceAttribute()
{
    if ( ! array_key_exists('highestPrice', $this->relations)) $this->load('highestPrice');

    $related = $this->getRelation('highestPrice');

    return ($related) ? $related->aggregate : null;
}

// now it's getting pretty simple
$products->first()->highestPrice; // highest price value we need
like image 111
Jarek Tkaczyk Avatar answered Jan 01 '23 19:01

Jarek Tkaczyk