Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to order by another table join by eager loading in Laravel

Tags:

laravel-4

I got product and stocks table;

products

id int
name varchar
created_at timestamp

stocks

id int
name varchar
product_id varchar
created_at timestamp

Product Model

public function validStock() {
    return $this->hasMany('Stock')->where('quantity', '>', 10);
}

If both have created_at, how to order by stocks's created_at, I've tried two methods and it's not work

Product::with('validStock')->orderBy('validStock.created_at', 'DESC');

Product::with(array('validStock' => function($q) {
    $q->orderBy('created_at', 'DESC');
}));
like image 558
Chan Avatar asked Nov 26 '13 11:11

Chan


People also ask

What is join query in Laravel?

What is Laravel Join? With the help of join queries in Laravel, one can add two or more tables. It is helpful in integrating large disparate sets of tables into one singular point of reference. Laravel Inner Join: This clause selects the records only if the selected values of the given column matches both the tables.

How to join two or multiple tables in Laravel?

Note that, you can also join two or multiple tables using laravel left, rigth and cross join. Laravel JOIN eloquent returns all rows from the both table, if there are matches in the both table. Otherwise, the result is NULL.

How to use MySQL order by in Laravel?

As you can see it in the Laravel documentation eager loading happens in 2 query. If you want to use MySQL's ORDER BY you have to join the related tables. As a workaround, you can run your query and sort the resulting collection with sortBy, sortByDesc or even sort.

What is cross join in Laravel?

Laravel Cross Join Clause: The Laravel Cross Join clause allows every row from Table 1 to join with every row from Table 2. Laravel Advanced Join Clauses: In this clause, other functionalities can be included into the command set. Queries like “where” and “orwhere” can be used to compare column with values.


1 Answers

Instead of sorting after retrieving all data (which is impossible to do in an efficient way when paginating results) you can use a join.

(This answer is based on this one.)

Product::with('validStock')
    ->join('stocks', 'stocks.product_id', '=', 'products.id')
    ->select('products.*') // Avoid selecting everything from the stocks table
    ->orderBy('stocks.created_at', 'DESC')
    ->get();

The only thing I don't like about this is that it takes away some of the database abstraction, in that you have to write your table names here.

Note that I haven't tried this with a hasMany relationship in this direction, as you have it in your example (selecting products, and each product has many stocks). I've tried only with the hasMany in the other direction (eg selecting stocks, each of which has exactly one product).

like image 55
tremby Avatar answered Jan 03 '23 12:01

tremby