0

I have been getting an error 'Method Illuminate\Database\Eloquent\Collection::latest does not exist' on this line of my code

     $items=Item::select('*')
    ->orderBy('version','DESC')
    ->get()
    ->unique('name')->latest()->paginate(5);

I'm not really sure why and how should I change my code?

Dharman
  • 30,962
  • 25
  • 85
  • 135
x_l_m_25
  • 7
  • 5
  • If you have a new question please use the search option to look for possible solutions. If you can't find any, consider posting a new question. Do not add a new problem to the existing question – Dharman Apr 15 '22 at 12:19

2 Answers2

1

latest() is a Builder class method not a Collection class method see: https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Builder.html#method_latest

So use it before getting the collection by get() or paginate():

$items=Item::select('*')
    ->orderBy('version','DESC')
    ->latest()
    ->get()
    ->unique('name');

Using pagination on unique values is a bit more complicated. We would need to know what to select if there is more records with the same name. The most simple approach is to use distinct() but this may not be what you need:

$items=Item::select('*')
    ->orderBy('version','DESC')
    ->latest()
    ->distinct()
    ->paginate(5);

Other possibility is to use groupBy('name') instead of distinct(), but there you must carefully aggregate the other columns around the 'name' (or select only the 'name' column). Example:

$items=Item::select('name', DB::raw('MAX(version) as max_version'))
    ->orderBy('max_version','DESC')    
    ->group_by('name')
    ->paginate(5);

If you need more columns selected use appropriate aggregate functions MAX() or FIRST(), LAST(), AVG(), etc..

To get the whole row (simple '*' cannot be used):

$max_version_table = Item::select('model_name', DB::raw('MAX(version) as max_version'))->groupBy('model_name');

$items = Item::select('*')->joinSub($max_version_table, 'max_version_table', function($join){
  $join->on('items.model_name','=','max_version_table.model_name');
  $join->on('items.version','=','max_version_table.max_version');
})->paginate(5);

Khamyl
  • 398
  • 2
  • 12
  • I tried using your code but changing name to *. Even though it only shows unique names, it doesn't show the highest version from my DB, https://imgur.com/a/dobHUuQ – x_l_m_25 Apr 15 '22 at 13:42
  • @x_l_m_25 you cannot change name to * just like that :) check the update – Khamyl Apr 15 '22 at 15:17
  • Thanks for your code, it works perfectly. However, can you explain to me what does the code do from joinSub? I'm kinda new to Laravel and these join functions confuse me. – x_l_m_25 Apr 16 '22 at 07:21
  • @x_l_m_25 Well join functions as well as all the other functions of eloquent database abstract layer is mostly about building blocks of an SQL request. The `joinSub` is one of them and it allows to implement `JOIN` command to the SQL query you are building. I was trying to build an SQL query (you needed) like this one here: https://stackoverflow.com/a/12102216/2039339. The `joinSub` created the `INNER JOIN` part of the query. To see what query you built use the `toSql()` as the last method instead of `paginate()` :) – Khamyl Apr 16 '22 at 09:46
0

Laravel's latest method doesn't work on the collection, it works on Query-Builder. So, first, use the latest method and then use paginate.

$items = Item::select('*')
     ->orderBy('version','DESC')
     ->latest()
     ->distinct()
     ->paginate(5);
  • Hi thank you for your reply, I tried using your code in but I am getting an error: Method Illuminate\Database\Eloquent\Collection::firstItem does not exist. and for links() as well in my index.blade.php. May I ask why? I edited the code in my post. – x_l_m_25 Apr 15 '22 at 12:05
  • Because `unique()` will return you a pure collection not a `LengthAwarePaginator` as you would expect. – Khamyl Apr 15 '22 at 12:13
  • @Khamyl Ah ok. I tried using groupBy and distinct but it doesn't return what I need, which is something like this post(https://stackoverflow.com/questions/58909566/laravel-group-by-and-order-by-not-working). Does that means I have to ditch the paginate and latest functions? – x_l_m_25 Apr 15 '22 at 12:21
  • @x_l_m_25 Maybe let me know what exactly you need, why you need the unique() function and I will update my answer ;) – Khamyl Apr 15 '22 at 12:23
  • @Khamyl I need to show the rows of the highest version of each model_name in my table. At first, I tried several ways like groupBy and orderBy (https://stackoverflow.com/questions/71870243/how-do-i-display-the-highest-value-of-the-column-in-laravel-using-eloquent) but they only show all the rows in my table sorted rather than showing what I wanted. I used the unique function as a way to filter out the rows that aren't the highest version of their model_name. Hope you understood what I'm writing :/ – x_l_m_25 Apr 15 '22 at 12:31
  • @x_l_m_25 check my updated answer – Khamyl Apr 15 '22 at 12:51
  • @x_l_m_25, I have got your point. I have updated my answer. Thanks – Mukti Rani Ghosh Apr 18 '22 at 03:59