How to take specifig column from relation ship in laravel - 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();

Related

How to use OrderBy in Laravel using eloquent relationship?

I have two model: Category and PostAd model.
They two have relation with each other.
In laravel view i have passed data through Category Model to display PostAd data.
I want to apply OrderBy condition in query but it doesn't work
Code
$data['category'] = Category::with(['postads'])->where('id',$id)->get();
I want to do this
$data['category'] = Category::with(['postads'])->where('id',$id)->orderBy('adtitle','DESC')->get();
But it doesn't work because it is Category Model.
How can i solve this.
if you want to get PostAd data with an order by then you can do an eager load Order by.
And here you're using get() method so it should be first(); because ->where('id',$id) always get one record.
$data['category'] = Category::with(['postads' => function($query) {
$query->orderBy('adtitle', 'DESC');
}])->where('id',$id)->first();

Where clause inside whereHas being ignored in Eloquent

Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.

Laravel 5.3 - multiple db queries when loading relations

I have posts table (id, user_id, title) and Post model with this content
class Post extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
I want to get some post by id and also the user's information, so I use this query
$post = new Post();
$res = $post->where('id', 1)->select('id', 'title', 'user_id')->with([
'user' => function ($query) {
$query->select('id', 'name', 'email');
}
])->first();
It returns the data as expected, and i can access the post's info like $res->title, or the user's info like $res->user->email, but the problem is it makes 2 queries to the database
I would expect to have one query only
SELECT
`posts`.`id`,
`posts`.`title`,
`posts`.`user_id`,
`users`.`id`,
`users`.`email`,
`users`.`name`
FROM
`posts`
LEFT JOIN `users`
ON `posts`.`user_id` = `users`.`id`
WHERE `posts`.`id` = '1'
LIMIT 1
Please note, this is not the same as N+1 problem
https://laravel.com/docs/5.3/eloquent-relationships#eager-loading
I know I can manually do left join,
$res = $post->where('posts.id', 1)
->select('posts.id', 'posts.title', 'posts.user_id', 'users.email', 'users.name')
->leftJoin('users', 'posts.user_id', '=', 'users.id')
->first();
and it will have the one query as I need, but the problem is in the result all data from related table is in the same array (and besides, what is the point of defining/using relationships if i have to manually make a left join every time)
So, my question is how to get the post data with related tables with one query and result organized according to relations: I am curious what is the best practice in laravel and how experienced Laravel developers are doing this ?
Thanks
Eloquent never uses JOINs to retrieve relationship data, but instead uses seperate queries and links the data together in PHP objects. Therefore, you will always have one extra query for each relationship. Also, Eloquent mostly loads all columns (using *).
To link them together, you have to stop using the query builder and instead use Eloquent directly:
$post = Post::find(1)->load('user');
If you insist on using JOINs, you will have to continue using the query builder.
That is eager loading.
You are using
->with([
'user' => function ($query) {
$query->select('id', 'name', 'email');
}
])
In eager loading, what happens is first run above query and get all the users matching the query.
Then the result is applied to the outer query which is
$post->where('id', 1)->select('id', 'title', 'user_id')->with([
'user' => function ($query) {
$query->select('id', 'name', 'email');
}
])->first();

Laravel Eloquent: eager loading of multiple nested relationships

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')

Laravel Eloquent ORM eager loading. Relation incorrectly returned as null

I have an Eloquent ORM relationship defined as follows:
ProductConfiguration:
public function product()
{
return $this->belongsTo('Excel\Products\Product');
}
public function currency()
{
return $this->belongsTo('Excel\Currencies\Currency');
}
Product
public function productConfigurations()
{
return $this->hasMany('Excel\Products\ProductConfiguration');
}
public function productType()
{
return $this->belongsTo('Excel\Products\ProductType');
}
I expect that if I do the following that I will load all product configurations of a specified product type, with the related products, nested product type details and the product configuration currency
$results = ProductConfiguration::with(
array(
'product' => function($query) use ($product_type) {
$query->where('product_type_id' , $product_type);
},
'product.productType',
'currency'
)
)
->get();
however the returned collection has 'product' set to NULL. the Currency Relationship is there, but the product relationship is not. I can see the outputted SQL queries and the query that selects the products retrieves the correct products if I paste it directly into my sql editor
select * from `products`
where `products`.`id` in ('12', '13')
and `product_type_id` = '1'
Am I correct to think that the results from this query should be included in my collection, or is there some obvious flaw in my thinking?
I think you don't want to achieve that. Now what you get is getting all ProductConfiguration with products that are only of certain_type.
So in case you have some configuration that has other type for product you will get null because you limited results from product to only the one that has certain product type.
I might be wrong, but you probably wanted to get those ProductConfiguration that belongs to Product that is type of certain_type. In this case you should use whereHas:
$results = ProductConfiguration::
with('product', 'product.productType', 'currency')->
whereHas('product', function($q) use ($product_type)
{
$q->where('product_type_id', '=', $product_type);
})->get();
I hate to post this as an answer but since i don't have enough rep to comment so try this first:
$results = ProductConfiguration::with('product')->get();
dd($results->toArray());
See what you get, if you get some data, try this
$results = ProductConfiguartion::with(array('products' => function($query){
$query->where('product_type_id' , $product_type);
})->get();
dd($results);
See what you get, if you get null: your $product_type variable may be something you didnt expect, so try dd($product_type) to make sure its what your expecting.

Resources