Order by belongsTo Relationship Column: Eloquent vs Query Builder

If you have a query with the belongsTo relationship and want to order the records by the column from that related table, the orderBy wouldn't work.

Example:

$products = Product::with('category')
->orderBy('category.name')
->get();

This code would throw an error: "Unknown column category.name in order clause"

To avoid such error, you could switch to using Query Builder with the join() method;

$products = Product::select(['products.*', 'categories.name as category_name'])
->join('categories', 'products.category_id', '=', 'categories.id')
->orderBy('categories.name')
->get();

The downside is more code to write. But this join() way is also faster because it runs ONE query to the database instead of two queries executed by with() during Eager Loading.


Alternative approaches

If you do want to use Eloquent, you may run the orderBy with a sub-select:

$products = Product::with('category')
->orderBy(Category::select('name')->whereColumn('categories.id', 'products.category_id'))
->get();

Also, if you have a really small amount of data and don't care that much about performance, you can get all the rows from the database and then use sortBy() on the collection.

$products = Product::with('category')
->get()
->sortBy('category.name');

Notice 1: the method name of Eloquent is called orderBy(), but the collection method is called differently sortBy()

Notice 2: use this sortBy() only if you are sure the DB table will not grow much bigger, otherwise downloading all the records will cause much bigger usage of the server RAM.

avatar

Could this be applied o example Ordering Data by Clicking Column Titles

avatar

Technically - yes. But that requires quite a bit of preparation to correctly prepare the database column and fields map.

I personally would recommend using some kind of a datatable for this, which supports that functionality as a package.

avatar

How if we want to order by with 2 realtion? For example Category have realtion to CategoryType So I want to orderBy() to column Product.Category.CategoryType.name

avatar

Solved!

$query->orderBy(Category::select('category_type.name')->whereColumn('categories.id', 'products.category_id')->join('category_types', 'category_types.id', 'categories.type_id'), 'asc');

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials