45

I have a model called School and it has many Students .

Here is the code in my model:

public function students()
{
    return $this->hasMany('Student');
}

I am getting all the students with this code in my controller:

$school = School::find($schoolId);

and in the view:

@foreach ($school->students as $student)

Now I want to order the Students by some field in the students table. How can I do that?

Debiprasad
  • 5,895
  • 16
  • 67
  • 95
  • @JaredFarrish orderBy there would affect query on the `schools` table, not `students`, and obviously would throw an error, unless you join the tables. – Jarek Tkaczyk Sep 06 '14 at 14:13

5 Answers5

106

You have a few ways of achieving this:

// when eager loading
$school = School::with(['students' => function ($q) {
  $q->orderBy('whateverField', 'asc/desc');
}])->find($schoolId);

// when lazy loading
$school = School::find($schoolId);
$school->load(['students' => function ($q) {
  $q->orderBy('whateverField', 'asc/desc');
}]);

// or on the collection
$school = School::find($schoolId);
// asc
$school->students->sortBy('whateverProperty');
// desc
$school->students->sortByDesc('whateverProperty');


// or querying students directly
$students = Student::whereHas('school', function ($q) use ($schoolId) {
  $q->where('id', $schoolId);
})->orderBy('whateverField')->get();
Jarek Tkaczyk
  • 78,987
  • 25
  • 159
  • 157
  • 1
    How to sort collections by multiple properties of the model? For example, I want to sort by class and then by their name. `$school->students->sortBy('whateverProperty')->sortBy('anotherProperty');` does not work. It only sorts the collection by 'anotherProperty'. – Debiprasad Sep 07 '14 at 12:14
  • Here is a solution which works. It uses the closure. http://stackoverflow.com/a/25451441/225790 – Debiprasad Sep 07 '14 at 12:40
  • Yes, Mark Baker's linked solution is neat. Another solution would be `usort`. – Jarek Tkaczyk Sep 07 '14 at 13:41
  • @SajeebAhamed `xToOne` doesn't make sense to sort related models, so what is your question actually? – Jarek Tkaczyk Oct 03 '17 at 12:36
  • sortBy is perfect for me, still didn't need to use join... the only thing that I'm worried about is I'm doing sortBy in the views at the foreach – Kelvin Barsana Dec 06 '18 at 08:28
  • SortBy has saved me! I have it inside a foreach, the use is as classic SQL: @foreach ($carts->sortBy('attribute.product_id') as $cartItem) ... where 'attribute' is a hasOne Eloquent relation – gtamborero Jun 04 '19 at 23:11
43

you can add orderBy to your relation, so the only thing you need to change is

public function students()
{
    return $this->hasMany('Student');
}

to

public function students()
{
    return $this->hasMany('Student')->orderBy('id', 'desc');
}
fico7489
  • 7,931
  • 7
  • 55
  • 89
10

To answer the original question, the students dynamic property can also be accessed as a relationship method.

So you have this to fetch all students:

$students = $school->students;

Now as a relationship method, this is equivalent:

$students = $school->students()->get();

Given this, you can now add in some ordering:

$students = $school->students()->orderBy('students.last_name')->get();

Since eloquent will be performing a join, make sure to include the table name when referencing the column to order by.

You can also add this to your students method if you want to set a default order that $school->students will always return. Check out the documentation for hasMany() to see how this works.

Jason
  • 4,411
  • 7
  • 40
  • 53
4

For Many to one relation I found one answer on:

https://laracasts.com/discuss/channels/eloquent/order-by-on-relationship

$order = 'desc';
$users = User::join('roles', 'users.role_id', '=', 'roles.id')
  ->orderBy('roles.label', $order)
  ->select('users.*')
  ->paginate(10);

this can save day... of anyone

fdehanne
  • 1,658
  • 1
  • 16
  • 32
0

You can use this like this:

$students = $school->students()->orderBy('id', 'desc');

You can also use

$students = $school->students()->orderBy('id', 'desc')->paginate(10);
Farid Chowdhury
  • 2,766
  • 1
  • 26
  • 21