Sorting data with Eloquent

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
# Sorting Data with Eloquent: Mastering Nested Relationships I'm new to Laravel (switched from CI) and Eloquent ORM is still a bit of a mystery at some point! When you start working with Object-Relational Mappers like Eloquent, the real power often lies not just in fetching data, but in how you use the relationships to construct complex queries. Today, we're going to tackle a very common scenario: sorting parent records based on data within their related child records. This is where Eloquent truly shines, allowing us to write expressive, readable code instead of dropping into raw SQL every time. ## The Scenario: Sorting Posts by Comment Activity Let's set up the context you described. We have `posts` and `comments`. A user wants to retrieve all posts they have created, but they want these posts to be ordered based on when the comments on those posts were created. **Goal:** Retrieve all `posts` belonging to a specific `$user`, ordered by the `created_at` of their associated `comments`. ## Setting Up Eloquent Relationships Before diving into the query, we must ensure our models are correctly set up with the necessary relationships. This is the foundation of using Eloquent effectively. In your `Post` model: ```php // app/Models/Post.php public function comments() { return $this->hasMany(Comment::class); } ``` And in your `Comment` model: ```php // app/Models/Comment.php public function post() { return $this->belongsTo(Post::class); } ``` ## The Eloquent Solution: Ordering Through Relationships Since we need to sort the parent `posts` based on a property of the related `comments`, we will use a combination of `whereHas` (to filter posts that actually have comments) and `orderBy` combined with the relationship. The key is to tell Eloquent exactly which relationship branch to use for sorting. We want to order the posts by the *earliest* or *latest* comment time associated with them. Here is how you structure the query: ```php use App\Models\Post; use Illuminate\Database\Eloquent\Builder; class PostController extends Controller { public function index(Request $request) { $userId = $request->user()->id; $posts = Post::whereHas('comments', function (Builder $query) use ($userId) { // Filter comments to only those belonging to the current user $query->where('user_id', $userId); }) // Now, order the resulting posts based on the related comment's created_at ->with('comments') // Eager load the comments for convenience ->orderBy('comments.created_at', 'asc') // Order by the comment time ->whereHas('comments', function (Builder $query) use ($userId) { // Ensure we only consider posts that have at least one relevant comment $query->where('user_id', $userId); }) ->with('comments') // Eager load the comments again if needed, or just rely on the initial load ->get(); return view('posts.index', compact('posts')); } } ``` ### Explanation of the Fluent Approach 1. **`whereHas('comments', function (Builder $query) use ($userId) { ... })`**: This is crucial. It filters the `posts` table to only include posts that have at least one related record in the `comments` table matching our criteria (i.e., a comment made by `$userId`). 2. **`orderBy('comments.created_at', 'asc')`**: Once filtered, we apply the ordering. Because we are using a relationship (`comments`) within the scope of the query builder, Eloquent knows exactly which table to reference for sorting. We explicitly tell it to sort by the `created_at