Alana Storm
Alana Storm

Reputation: 166086

Ordering Related Models with Laravel/Eloquent

Is it possible to use an orderBy for an object's related models? That is, let's say I have a Blog Post model with a hasMany("Comments"); I can fetch a collection with

$posts = BlogPost::all();

And then run through each post, and display the comment's last edited date for each one

foreach($posts as $post)
{
    foreach($post->comments as $comment)
    {
        echo $comment->edited_date,"\n";
    }
}

Is there a way for me to set the order the comments are returned in?

Upvotes: 5

Views: 7160

Answers (4)

MartinG
MartinG

Reputation: 183

Create a JOIN and select just the column you want to order on:

$post = BlogPost::join('comments', function($j) {
        $j->on('posts.id', '=', 'comments.post_id');
        $j->select('comment_date_or_other_col');
     })
     ->orderBy('comment_date_or_other_col', 'DESC')->first();

Upvotes: 1

totymedli
totymedli

Reputation: 31108

The returned object from the relationship is an Eloquent instance that supports the functions of the query builder, so you can call query builder methods on it.

foreach ($posts as $post) {
    foreach ($post->comments()->orderBy('edited_date')->get() as $comment) {
        echo $comment->edited_date,"\n";
    }
}

Also, keep in mind when you foreach() all posts like this, that Laravel has to run a query to select the comments for the posts in each iteration, so eager loading the comments like you see in Jarek Tkaczyk's answer is recommended.

You can also create an independent function for the ordered comments like you see in this question.

public function comments() {
    return $this->hasMany('Comment')->orderBy('comments.edited_date');
}

And then you can loop them like you did in your original code.

Upvotes: 3

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81187

This is the correct way:

BlogPost::with(['comments' => function ($q) {
  $q->orderBy('whatever');
}])->get();

Upvotes: 20

Antonio Carlos Ribeiro
Antonio Carlos Ribeiro

Reputation: 87769

Yes:

$posts = BlogPost::with('comments')
           ->orderBy('comments_table_name.column_name')
           ->get();

And you can also set that in your relation:

public comments()
{
    $this->hasMany("Comments")->orderBy('comments.column_name');
}

Upvotes: -3

Related Questions