Laravel Eager Loading, only when ids are available - php

I have a table like this:
payments
-id
-client_id
-vendor_id
-product_id
-item_id
-..._id
Using Laravel's eager loading, I can do this ->load('client', 'vendor' ... ) and load the relationships for all the returned rows of payments. But I've noticed that for example when there are no values in payments for vendor_id the eager loading query for the "vendor" relationship still happens, as below:
select * from `vendors` where `vendors`.`id` in ('')
The in ('') I understand should be filled with the values for vendor_id in the payments table, but since there were none the above query should not happen, right?! Is that a bug in Laravel?
The problem is that i got like 20 [x]_id columns in this payments table, and in each row only a couple (varies for each row) [x]_id columns have values, and I don't want to make 20 extra eager-loading queries, just the ones needed based on the actual existence of these ids!

When you are doing lazy eager loading, laravel does not know if records are present or not. If not present laravel returns empty collection.
If you want to filter out at the start itself to show only payments having vendors and clients etc, you can do :
$payments : Payment::whereHas('vendors')->whereHas('clients')->get();
Above will give you only payments which contain at-least one vendor and 1 client.
Also, you are using load() which is lazy-eager loading. It is designed so that you can get the primary collection first and later when and if you need, then only get the relation collection.
Check for with() if you do not want to lazy-eager load.
Also, if you want to avoid eager loading, you can go for join but again then you wont be using defined relations.

Related

Eloquent Models with hasMany WHERE condition

I'm fairly new to Laravel 5.5 and Eloquent, so I'm struggling to work out how to do this using Eloquent objects.
If I was going to do this in SQL it would be pretty simple, but I'd prefer to deal in Eloquent objects.
I have two tables, Lots and Bids and I have the models that go with these.
Is there a way to get any Lot model where a specific user has bid on it (user_id column in the bids table), and then get the maximum bid amount that the user has bid?
Thanks to Devon, I used the whereHas to return the models that I needed. I then added another method to the model that returned the max bid price.

Laravel eloquent 5.3 Eager/Lazy loading related models with multiple limit

I'm leveraging Laravel's eloquent by Lazy/Eager Loading and have come across an interesting issue.
Description:
An account has many groups, each with a priority number
All groups Contain Items in them
The issue:
I need to manually set a limit to the number of returned items of each group
The difference here is that the limit number changes based on each groups priority level
So, for example, the eloquent "select" statement would get all three groups but limit the number of items returned in group 1 to just 3 items, group 2 to just 8 items, group 3 to 17 items.
What I've tried to do:
Code in Controller to get records
return Account::with([
'group_list.item'
])->where('group_id', $my->group_id)
->orderBy('group_priority_num', 'ASC')
->take(3) <----Gets three groups
->get(['group_priority_num','group_title','group_id']);
Group Model
public function group_list() {
// Example
$this->number = [4 , 7, 15];
return $this->group()->limit($this->number)->groupBy('user_group_id_fk');
}
This only returns 1 record or none at all, so I'm currently confused about how to approach this correctly. Can someone lend me some guidance on this?
Any assistance is greatly appreciated, Thank you in advance.
Cheers!
Eager loading is implemented via a second query using WHERE foreign_key_column IN (list of primary model IDs). With such a query it is impossible to set a limit on per model basis unless there's some other condition that the results can be further filtered by.
You have 3 options:
Let Eloquent eager load everything and filter the results in PHP according to your needs.
Perform the eager loading your self by fetching only the primary model followed by separate queries for each model's relationships with their respective limits.
Add a flag column to your groups table that would let you mark the rows that should be returned for each group.

Sorting by nested eager loaded relationships (with pagination)?

I am currently developing a system to filter and display data that is used via Eloquent and saved to the database in the following way:
Catalog -(1)---(n)-> Product -(1)---(n)-> Group -(n)---(n)-> Part
Product -(n)---(n)-> Provider
I'm eager loading these models completely and then display their attributes in my view as a table, the columns I base on user settings. Now I'm trying to add a way to order (and search through) these columns, but I can't seem to figure out any way to be able to order the whole result (Catalog is ultimately the 'master' collection) by any nested attributes.
For parts and providers (n:n relationships) I only need to be able to order the result by either the first or the last one's attributes.
Can anyone help me out here? I tried joins, but I can't figure out how to join both the first element and the last element for those two models and somehow distinguish them.

Laravel Inserting nested Eloquent ORM model

Suppose I have three tables with relationships like below:
product
has many options
option
can belong to many product
has option_values
option_value
belongs to many option
Using Laravel I can update option like this
product->options()->insert($stuff);
However I want to insert into the option_value as well.
I tried
product->options()->values()->insert($otherStuff);
But that doesnt work. How can this be done with Eloquent ORM?
You can't access a sub-relationship this way, you have to actually have the model result and call the method on it, or use eager loading but eager loading does not help with an insert.
You would have to loop the option models and insert trough them, but that results in way too many insert queries. Better may be to just grab the related ids and run the insert in a single fluent query instead of many Eloquent.
$option_ids = $product->options()->lists('id');
DB::table(OptionValue::$table)->insert(array_merge($data, $option_ids));

CakePHP Pagination with conditions on has_many

So I have a User table and a History table with User hasMany Histories, and I'm trying to implement pagination on the user table.
My problem is that I have search, and some of the things one can search by are things in the History table. Is there a way to filter pagination results based on data in a table associated by hasMany? Containable, which initially seemed like a solution, allows such filtering but only in the retrieval of associated data, not the records themselves (unless I'm missing something?)
Has anyone had to solve this before?
Since it's a hasMany relationship, that means Cake will need to make 2 separate queries: 1 on the users table, and one on the histories table to retrieve all the associations. Since the History data isn't being retrieved until the 2nd query, then your 1st query cannot be filtered via WHERE conditions for fields found in the History model.
To resolve this, you can do one of two things:
Perform pagination on History using Containable (since History belongsTo User, meaning only 1 query will be performed).
Perform pagination on User the way you're already doing, except perform an ad-hoc join to History such that it's no longer a hasMany relationship.
e.g.:
$this->User->bindModel(array('hasOne' => array('History')));
$this->paginate['User']['contain'][] = 'History';
$this->paginate('User', array('History.some_field' => 'some_value'));

Categories