How to Use orderBy() (and more) for Sorting Eloquent Query Results

July 11th, 2024 • 4 minutes read time

Ordering in Laravel is pretty straightforward, but you can use a few other techniques to make the most of Eloquent's ordering abilities. Let's cover everything you should know about ordering queries with Laravel!

The most basic ordering with Eloquent starts with the orderBy method. Here's what it looks like:

$posts = Post::orderBy('published_at', 'desc')->get();

The first argument (published_at here) is the column you want to order by. This can be any column type. In this case, it's a datetime.

The second argument is the direction you want to sort in (either desc for descending or asc for ascending).

So, if you wanted to fetch all posts and show the latest first, you'd order by the created_at or published_at date in descending (desc) order.

But wait, there's even a method for sorting specifically in descending order if you prefer this to passing in a second argument:

$posts = Post::orderByDesc('published_at')->get();

Most of the time, you'll order by the latest or oldest records. Laravel has some built-in scopes that make this much easier to write.

To order with the latest at the top:

$posts = Post::latest()->get();

To order with the oldest at the top:

$posts = Post::oldest()->get();

By default, these two scopes will use the created_at date, but you can pass in the column you'd like to use:

$posts = Post::latest('published_at')->get();

Behind the scenes, these Eloquent scopes use the orderBy method – this is just syntactic sugar to make it easier to write and read.

How can you sort by multiple columns in Eloquent? Well, just use the orderBy method twice!

Here's an example of ordering by multiple columns:

$posts = Post::orderBy('title', 'desc')
    ->orderBy('published_at', 'asc')
    ->get();

In this example, multi-column ordering works by first ordering by title and then by published_at if two titles exist with the same value. Pretty unlikely in the case of a blog post, but apply this to your own queries where it makes sense.

Because Eloquent relationships return a Builder, we can directly order when we define these relationships.

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class)
            ->latest();
    }
}

We're using the latest scope here, but you can use any ordering technique directly chained onto the relationship to always order it when accessed.

You can clear previously ordered queries in Eloquent using the reorder method. This is useful if you're always ordering a relationship in a certain way but need to undo it for a particular case.

Let's take the relationship we looked at in the last section:

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class)
            ->latest();
    }
}

Any time we access posts from a user, they'll always be ordered by created_at in desc order.

To clear ordering wherever you need, use reorder:

$posts = auth()->user()
    ->posts()
    ->reorder()
    ->oldest()
    ->get();

We've used reorder to clear the previous order before using oldest to perform the new order.

You can do this all in one hit by passing some arguments through to reorder:

$posts = auth()->user()
    ->posts()
    ->reorder('created_at', 'asc')
    ->get();

This means you don't need to use orderBy, oldest or any other ordering functionality — reorder will do it all in one go.

If you need to randomly order results with Eloquent, use the inRandomOrder method:

$posts = Post::inRandomOrder()->get();

Behind the scenes, this will use an SQL RANDOM() function to seed the query with a random order, perform a raw query, and return your results randomly ordered.

Just be aware that this will result in a slightly slower query, so it's best to cache your results for a short period if you can.

If you need to order with a raw query in Eloquent, you can use orderByRaw:

$posts = Post::orderByRaw(`created_at DESC`)->get();

This example just orders in the same way latest or orderBy would, but you can pass any valid SQL in here.

We've already seen an example of ordering randomly, but here's how this would look with orderByRaw:

$posts = Post::orderByRaw(`RANDOM()`)->get();

If you find yourself repeating a specific order throughout your application, creating a scope to deal with this helps tidy things up.

On your model, define a new scope:

class Post extends Model
{
    public function scopeOrderByPublishedDate($query)
    {
        $query->orderBy('published_at', 'desc');
    }
}

Any scopes you create should be prefixed by scope, followed by the name of your scope.

Now you've defined a scope, use it like this:

$posts = Post::orderByPublishedDate()->get();

Now, rather than use orderBy('published_at', 'desc') throughout your application, you can use a scope, which is much easier to type, read, and remember.

If you found this article helpful, you'll love our practical screencasts.
Author
Alex Garrett-Smith
Share :

Comments

No comments, yet. Be the first!