f7n
f7n

Reputation: 1684

How to re-order an Eloquent collection?

I've got a collection of records retrieved via a relationship, and I'd like to order them by the created_at field. Is this possible in Eloquent?

Here is how I am retrieving the collection:

$skills = $employee->skills;

I'd like to order this $skills collection by their creation. I've tried $skills->orderBy('created_at', 'desc'); but the Collection class does not have an orderBy method.

I guess this problem is very simple and I'm missing something..

Upvotes: 1

Views: 2243

Answers (6)

Robin Bastiaan
Robin Bastiaan

Reputation: 702

This Stackoverflow question askes how to order an Eloquent collection. However, I would like to propose a different solution to use instead given the example in the question. I would like to recommend to use an ordering on the query itself for performance reasons.

Like @Don't Panic proposes you can specify a default ordering on the relationship for great reusability convenience:

app/Models/Employee.php

public function skills() {
    return $this->hasMany(Skills::class)->orderBy('created_at');
}

However, if you have already set an ordering on your query like we do in the code above, any additional orderings will be ignored. So that is a bummer if you want to use a different sorting in another situation. To overwrite this default ordering and re-order the query with a new ordering, one needs to use the reorder() method. For example:

// Get a Collections of Skill-models ordered by the oldest skill first.
$skills = $employee->skills()->reorder()->orderByDesc('created_at')->get();

// Same result as the previous example, but different syntax.
$skills = $employee->skills()->reorder()->oldest()->get();

// Or just give some arguments to the reorder() method directly:
$skills = $employee->skills()->reorder('created_at', 'desc')->get();

Upvotes: 1

Nauman Zafar
Nauman Zafar

Reputation: 1103

You can do this in two ways. Either you can orderBy your results while query, as in

$employee->skills()->orderBy('created_at', 'desc')->get();

OR

You can use sortBy and sortByDesc on your collection

Upvotes: 4

Sandeesh
Sandeesh

Reputation: 11906

Collection has sortBy and sortByDesc

$skills = $skills->sortBy('created_at');
$skills = $skills->sortByDesc('created_at');

Upvotes: 0

Don't Panic
Don't Panic

Reputation: 14520

If you want the results to always be ordered by a field, you can specify that on the relationship:

Employee.php

public function skills() {
    return $this->hasMany(Skills::class)->orderBy('created_at');
}

If you just want to order them sometimes, you can use orderBy(), but on the relationship, not the property:

$skills = $employee->skills()->orderBy('created_at')->get();

Upvotes: 0

James O'Neill
James O'Neill

Reputation: 416

The reason this is failing is that orderBy is a query method not a collection method.

If you used $skills = $employee->skills()->orderBy('created_at', 'desc')->get();, this would query the skills in the order you want.

Alternatively, if you already had a collection that you wanted to re-order, you could use the sortBy or sortByDesc methods.

Upvotes: 1

Mozammil
Mozammil

Reputation: 8750

You need to add the orderBy constraint on the query instead of the relationship.

For e.g,

$employees = Employee::where('salary', '>', '50000') // just an example
                      ->with('skills')  // eager loading the relationship
                      ->orderBy('created_at', 'desc')
                      ->get();

and then:

foreach($employees as $employee) 
{
    var_dump($employee->skill);
}

Upvotes: 0

Related Questions