I've found the concept and meaning behind these methods to be a little confusing, is it possible for somebody to explain to me what the difference between has
and with
is, in the context of an example (if possible)?
In my application I have updated a relationship from one-to-many
to many-to-many
and I'm trying to figure out a way to persist associated functionality.
Let's say I have two related tables, e.g. dogs and owners. If I have an array of owners and I'm trying to get a list of dogs id's for those owners, how should I do it eloquently?
Similar question was asked here: https://laracasts.com/discuss/channels/laravel/getting-many-to-many-related-data-for-an-array-of-elements
Owner::with('dogs')->get(); // will return all owners and their dogs
So, How would I get the Dog
models where Owner
is in an array ?
Same thing as $associatedDogs = Dog::whereIn('owner_id',$ListOfOwners)->get();
is for a One-To-Many
relationship, but for Many-to-Many
.
Use the whereHas()
method:
$dogs = Dog::whereHas('owners', function($q) use($ownerIds) {
$q->whereIn('id', $ownerIds);
})->get();
- Should I choose the
whereHas
overwith
? What is the difference between them in this case? Does it even make any difference? – Angelin Calu Mar 9 '17 at 10:01 - Nevermind, I found the explaination here: stackoverflow.com/a/30232227/2012740 – Angelin Calu Mar 9 '17 at 10:28
- @AngelinCalu yes,
with()
will not work for you, since it loads relation data. – Alexey Mezenin Mar 9 '17 at 13:15 - @ I haven't actually tried the
with
method because of what I have read. So if I understood correctly, that it will probably work also, however it will eager load theowner
s associated with thedog
s – Angelin CaluMar 9 '17 at 13:20 - 1@AngelinCalu no
with()
will not work. It will load all dogs and filtered owners.whereHas()
will load only dogs with owners which are in the list. Just try both and you'll see the difference. – Alexey Mezenin Mar 9 '17 at 13:28
Try
$associateDogs = Dog::with(['owners' => function($query) use ($listOfOwners) {
$query->whereIn('id', $listOfOwners);
}])->get();
来自 https://stackoverflow.com/questions/42691421/laravel-eloquent-many-to-many-query-wherein
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
- 52+1, very helpful answer! Note also that while
with('relation')
will include the related table's data in the returned collection,has('relation')
andwhereHas('relation')
will not include the related table's data. So you may need to call bothwith('relation')
as well ashas()
orwhereHas()
. – SoulriserFeb 6 '16 at 16:08 - Greet Answer, How to access parent model from relationship model for instance here how to search post model based on the attributes of user model – hussainfrotan May 12 '17 at 5:53
- @BhojendraNepal Unfortunately there doesn't seem to be a lot about it in the docs... This is all I found (it's a few paragraphs down) – lukasgeiter Jul 25 '17 at 21:00
- @hussainfrotan the same way, use
whereHas
on user relation when querying post. – Michael Tsang Nov 12 at 5:35
So I have a products
table and a categories
table and a pivot
table.
Product (products
)
-- id
-- name
Category (categories
)
-- id
-- name
CategoryProduct (category_product
)
-- category_id
-- product_id
I want to get all products that belong to a certain category, I have managed to get it by doing the following query:
$products = Category::find(3)->products;
But how can I access it off the product model?
$products = Product::?
You need the whereHas
clause. https://laravel.com/docs/5.4/eloquent-relationships#querying-relationship-existence
$products = Product::whereHas('categories', function ($query) {
return $query->where('id', 3);
})->get();
Or you can do it with a join instead.
$products = Product::select('products.*')
->join('category_product', 'products.id', '=', 'category_product.product_id')
->where('category_product.category_id', 3)
->groupBy('products.id')
->get();
- SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous. That is the error I get when I run your code – robertmylne May 3 '17 at 5:18
- Which snippet gives that error? Did you add any other clauses, scopes, etc? – fubar May 3 '17 at 5:21
Getting many to many related data for an array of elements
Let's say I have two related tables, e.g. dogs and owners. If I had few owners which dogs names I'd like to get, how should I do it eloquently and dynamically?