Laravel Eloquent: eager loading of multiple nested relationships - laravel

What laravel says:
$books = App\Book::with('author.contacts')->get();
What I need is something like this
$books = App\Book::with('author[contacts,publishers]')->get();
where we eager load multiple relationships within a relationship.
Is this possible?

You can do
$books = App\Book::with('author.contacts','author.publishers')->get();

Laravel documentation on eager loading recommends listing the relationships in an array as follows:
$books = App\Book::with(['author.contacts', 'author.publishers'])->get();
You can have as many relationships as desired. You can also specify which columns should be included for a relationship like this:
//only id, name and email will be returned for author
//id must always be included
$books = App\Book::with(['author: id, name, email', 'author.contacts', 'author.publishers'])->get();
You may also add constrains as follows:
$books = App\Book::with(['author: id, name, email', 'author.contacts' => function ($query) {
$query->where('address', 'like', '%city%');
}, 'author.publishers'])->get();

So, now you can try
$books = App\Book::with(['author' => function($author){
$author->with(['contacts', 'publishers'])->get();
}])->get();

From Laravel 9, the neatest way is the nested array :
$books = App\Book::with(['author' => [
'contacts',
'publishers'
])->get();
Reference

When eager load nested relationships and we want to select just some columns and not all using relationship:id,name, always include the foreign key to the nested models, else they won't load at all.
Fort example, we have orders that have identities that have addresses.
This will not load the address:
User::orders()
->with('identity:id,name', 'identity.address:id,street')
This will load the address because we have supplied the address_id foreign key:
User::orders()
->with('identity:id,address_id,name', 'identity.address:id,street')

Related

How to take specifig column from relation ship in laravel

I am getting Consignment model which belongsTo Product type model so when i try to access name of product type i use this query
$consignment->product_types->name
But checked that this queries mean
select* from product_types
In my projectti am using this method many places which is now creating issue. Is there any method i can just take specific columns?
You may specify which relationships should be eager loaded using the [with] method:
$companies = Company::select('id', 'name', 'phone')
->with('customers:id,company_id,name')
->get();
echo '<pre>';
print_r($companies->toArray());
you can restrict it in your query builder:
Consignment::with(['product_types' => function ($query) {
$query->select("id", "consignment_id", "name");
}])->get();

Laravel with-count subquery without relation

My target is to get collection of books with count of matches book.names in another table without relation
I get collection like this
$books = Books::paginate(20);
What I need now is to get the count of matches like this
SELECT COUNT(*) FROM `posts` WHERE `body` LIKE '%book.name%'
How can I do this with one query and avoiding unnecessary queries for each model, like eager loading
You can do it with eager loading without loading all post. There is a method called withCount
Books.php
public function posts() {
return $this->hasMany(Post::class, 'post_id', 'id');
}
One way to find all post related to book is
$books = Books::withCount(['posts' => function ($query) use($searchTerm) {
$query->where('body', 'like', $searchTerm);
}])->get();
//How to retrieve
$book = $books->first()->posts_count.
You can find more information about withCount on laravel documentation website.
Approach 2: Without Eager Loading
$books = Books::select('*')->addSelect(DB::raw("SELECT COUNT(*) as post_count FROM `posts` WHERE `body` LIKE '%book.name%' ")->get(); //This will return collection with post_count.
Note: Not tested

Laravel: Limit columns retrieve in an eagerly loaded relationship, with constraints

When I eagerly load a straightforward Eloquent relationship I can limit the columns retrieved using the following syntax:
MyModel::with(myRelation:id,col_2,col_3);
When I want to constrain the members of the relationship, I do this:
MyModel::with(['myRelation' => function ($query) {
$query->where([
['field_1', 'a_value'],
['field_2', 'b_value']
]);
}]);
But that loads all columns of the related models. I tried replacing the key myRelation with the full syntax, myRelation:id,col_2,col_3, but it throws an error which says the relation name is not found.
I also tried adding the following methods to the $query:
->select('id', 'col_2', 'col_3')
or
->addSelect('id', 'col_2', 'col_3')
or
->get('id', 'col_2', 'col_3')
None of these were successful.
One option could be keeping all the columns (except id, col_2, col_3) hidden in your original model MyRelation is pointing to.
protected $hidden = ['col_4', 'col_5',...];
You could also change the relationship definition in your model MyModel:
public function myRelation()
{
return $this->belongsTo('MyRelation')->select(array('id', 'col_2', 'col_3'));
}
But, in general, this should work:
MyModel::with(array('myRelation'=>function($query){
$query->select('id','col_2', 'col_3)
->where([
['field_1', 'a_value'],
['field_2', 'b_value']
]);
}))->get();
Remember, you have to include the joining key (say id) in the select list above.
Ok, so to get this to work, I had to:
include the foreign_key in the list of selects (thanks, #ankitPatel), and
pass the parameters to the select statement as an array, as follows:
->select(['id','foreign_key','col3','col4'])

User::all show relationship items

I Laravel 5.5 I am returning users information like this...
$users = User::all();
return Response::json(array(
'error' => false,
'response' => $users,
));
I have a belongs to many categories relationship setup and would like to also show all of the categories each user belongs to.
Anyone have an example I can see?
Use the with() method to load categories for each user:
$users = User::with('categories')->get();
If you don't need to load all the columns from the categories table, use select() inside the with() closure. Also, since you're using Laravel 5.5 you could use Resource classes for formatting JSON.

Laravel 5 eloquent: select specific column of relation

I have 2 models: Author and Post
In my Post model, I have an author function (One To Many (Inverse)):
public function author()
{
return $this->belongsTo('App\Author', 'author_id');
}
Now I want to export to Excel the following information:
id | title | author name
This is what I tried:
$posts = Post::with(array(
'author' => function ($query) {
$query->select('name');
}))->select('id', 'title')->get();
What I get is an empty author's name column.
What do I wrong?
Since Laravel 5.5 you can use eager loading retrieve multiple specific columns simply by using string
Post::with('author:id,name')->get()
Author::with('posts:id,author_id,title')->get()
Notice the id or foreign key (author_id) must included, or data will be null.
please try:
$posts = Post::with(['author' => function($query){
$query->select(['id','name']);
}])->get(['id','title', 'author_foreign_key_in_posts_table']);
Having that, you'll be able to get:
$posts->first()->author->name;
$posts->first()->id;
$posts->first()->title;
You may use iteration or whatever instead of first() for export.

Resources