Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean? Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean? laravel laravel

Laravel - Eloquent "Has", "With", "WhereHas" - What do they mean?


With

with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.

Example:

User > hasMany > Post

$users = User::with('posts')->get();foreach($users as $user){    $users->posts; // posts is already loaded and no additional DB query is run}

Has

has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.

Example:

User > hasMany > Post

$users = User::has('posts')->get();// only users that have at least one post are contained in the collection

WhereHas

whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.

Example:

User > hasMany > Post

$users = User::whereHas('posts', function($q){    $q->where('created_at', '>=', '2015-01-01 00:00:00');})->get();// only users that have posts from 2015 on forward are returned


Document has already explain the usage.So I am using SQL to explain these methods

Example:


Assuming there is an Order (orders) has many OrderItem (order_items).

And you have already build the relationship between them.

// App\Models\Order:public function orderItems() {    return $this->hasMany('App\Models\OrderItem', 'order_id', 'id');}

These three methods are all based on a relationship.

With


Result: with() return the model object and its related results.

Advantage: It is eager-loading which can prevent the N+1 problem.

When you are using the following Eloquent Builder:

Order::with('orderItems')->get();

Laravel change this code to only two SQL:

// get all orders:SELECT * FROM orders;  // get the order_items based on the orders' id aboveSELECT * FROM order_items WHERE order_items.order_id IN (1,2,3,4...);

And then laravel merge the results of the second SQL as different from the results of the first SQL by foreign key. At last return the collection results.

So if you selected columns without the foreign_key in closure, the relationship result will be empty:

Order::with(['orderItems' => function($query) {            // $query->sum('quantity');           $query->select('quantity'); // without `order_id`       }])->get();#=> result:[{  id: 1,    code: '00001',    orderItems: [],    // <== is empty  },{    id: 2,    code: '00002',    orderItems: [],    // <== is empty  }...}]

Has


Has will return the model's object that its relationship is not empty.

Order::has('orderItems')->get();

Laravel change this code to one SQL:

select * from `orders` where exists (    select * from `order_items` where `orders`.`id` = `order_items`.`order_id`)

whereHas


whereHas and orWhereHas methods to put where conditions on your has queries. These methods allow you to add customized constraints to a relationship constraint.

Order::whereHas('orderItems', function($query) {   $query->where('status', 1);})->get();

Laravel change this code to one SQL:

select * from `orders` where exists (    select *     from `order_items`     where `orders`.`id` = `order_items`.`order_id` and `status` = 1)