Laravel framework relation has in implement

v2.1.1 2022-09-05 07:57 UTC


English | 中文


68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d3733383944382e7376673f7374796c653d666c6174 68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f62696969696969676d6f6e737465722f686173696e2e7376673f636f6c6f723d343039394445 68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f62696969696969676d6f6e737465722f686173696e2e7376673f636f6c6f723d 68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382b2d3539613966382e7376673f7374796c653d666c6174

The hasin is composer package based on where in syntax to query the relationship of laravel ORM, which can replace has based on where exists syntax in some business scenarios to obtain higher performance.


Laravel Version Install command
Laravel 9 composer require biiiiiigmonster/hasin:^2.0
Laravel 5.5 ~ 8 composer require biiiiiigmonster/hasin:^1.0


The relationship of laravel ORM is very powerful, and the query has based on the relationship also provides us with many flexible calling methods. However, in some cases, has is implemented with where exists syntax.

For example:

// User hasMany Post

select * from users where exists (select * from posts where = posts.user_id)

'exists' is a loop to the external table, and then queries the internal table (subQuery) every time. Because the index used for the query of the internal table (the internal table is efficient, so it can be used as a large table), and how much of the external table needs to be traversed, it is inevitable (try to use a small table), so the use of exists for the large internal table can speed up the efficiency.

However, when the User has a large amount of data, there will be performance problems, so the where in syntax will greatly improve the performance.

select * from users where in (select posts.user_id from posts)

'in' is to hash connect the appearance and inner table, first query the inner table, then match the result of the inner table with the appearance, and use the index for the outer table (the appearance is efficient, and large tables can be used). Most of the inner tables need to be queried, which is inevitable. Therefore, using 'in' with large appearance can speed up the efficiency.

Therefore, the use of has(hasMorph) or hasIn(hasMorphIn) in code should be determined by data size

 * SQL:
 * select * from `users` 
 * where exists 
 *   ( 
 *      select * from `posts` 
 *      where `users`.`id` = `posts`.`user_id` 
 *   ) 
 * limit 10 offset 0
$users = User::has('posts')->paginate(10);

 * SQL:
 * select * from `users` 
 * where `users`.`id` in  
 *   ( 
 *      select `posts`.`user_id` from `posts` 
 *   ) 
 * limit 10 offset 0
$users = User::hasIn('posts')->paginate(10);

Usage example

hasIn(hasMorphIn) supports all Relations in laravel ORM. The call mode and internal implementation are completely consistent with has(hasMorph) of the framework.


// hasIn

// orHasIn
User::where('age', '>', 18)->orHasIn('posts')->get();

// doesntHaveIn

// orDoesntHaveIn
User::where('age', '>', 18)->orDoesntHaveIn('posts')->get();


// whereHasIn
User::whereHasIn('posts', function ($query) {
    $query->where('votes', '>', 10);

// orWhereHasIn
User::where('age', '>', 18)->orWhereHasIn('posts', function ($query) {
    $query->where('votes', '>', 10);

// whereDoesntHaveIn
User::whereDoesntHaveIn('posts', function ($query) {
    $query->where('votes', '>', 10);

// orWhereDoesntHaveIn
User::where('age', '>', 18)->orWhereDoesntHaveIn('posts', function ($query) {
    $query->where('votes', '>', 10);


Image::hasMorphIn('imageable', [Post::class, Comment::class])->get();

Nested Relation



composer test

Tips: before testing, you need to configure your database connection in the phpunit.xml.dist.