Eloquent Relations: how to order topics by newest posts?

Quite a typical scenario, but not easy to find the answer. You can easily order Eloquent results by some column, but what if you want to order by related column in child table? Most common example is a forum like Laracasts which shows topics in order by the latest post in that topic. How to do that?

First, this is our relationship in app\Topic.php:

public function posts()
{
    return $this->hasMany(\App\Post::class);
}

Now, you need to realize that this wouldn’t work:

$topics = Topic::with('posts')->orderBy('posts.created_at')->get();

What we actually need to do – two things, actually:

1. Describe a separate relationship for the latest post in the topic:

public function latestPost()
{
    return $this->hasOne(\App\Post::class)->latest();
}

2. And then, in our controller, we can do this “magic”:

$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');

Let’s test it out – here’s our topics table.

laravel topics

Now, let’s show all users order by latest post.
If you look at the data, user ID 2 should come first with latest post on 27th day, then user ID 3 with post on 26th day, and then user ID 1 with post on 25th.

$users = User::with('latestPost')->get()->sortByDesc('latestPost.created_at');
foreach ($users as $user) {
    echo $user->id . ' - ' . $user->latestPost->title . ' (' . $user->latestPost->created_at . ')
'; }

Result:

laravel users

So, isn’t that sweet? You can read more about sortBy and sortByDesc methods here.

Like our articles?
Check out our Laravel online courses!

7 COMMENTS

  1. So weird, I was looking to solve this exact problem (in my case, it’s tags not topics, but I’m effectively using them as topics) and this post shows up in my RSS reader… Thumbs up and many thanks!

  2. What if I want to get most post count instead of latest!
    I meant to say that, I want to get topics sorted by which have most posts. Currently, I’m doing this by putting posts count in an array and then sort it.

  3. It doesn’t work in all cases but you can

    Model::where(‘column’, ‘someValue’)->(otherwheresetc)->join(‘relationship_table’, ‘model.id’, ‘=’, ‘relationship_table.model_id’)->orderBy(‘relationship_table.column_name’, ‘asc|desc’)->paginate();

    The other problem is you know longer have the model in a model format that you have when using with…

LEAVE A REPLY

Please enter your comment!
Please enter your name here