Lean Eloquent Results ->with() Eager Loading - laravel

I have a query I am working on that feeds into a javascript engine where there is a lot of information returned that isn't used in the javascript. The results are over 1MB and some of that is because of some eager loading. Here is the query:
$customers = Customer::where('customers.office_id', $officeid)
->where("customers.parent_id", null)
->with('lastAppointment')
->with('nextAppointment')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value")
->get();
The relationship of lastAppointment creates a returned nested object with all the columns from the appointments table, where I really only want a single column of start_at
If I do a ->leftJoin() I can limit my results using the final select like this:
->leftJoin(DB::raw("(select customer_id, MAX(start_at) as lastAppointment from appointments group by customer_id) as appt"), 'customers.id', '=', 'appt.customer_id')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value", "appt.lastAppointment")
I am just wondering if there is a way of doing something similar using ->with()?

You can use this code
->with('lastAppointment:_relation_id,start_at')
where _relation_id is customer_id or primary key of lastAppointment correspond model: depends on your table relation. See docs part of Nested Eager Loading
https://laravel.com/docs/5.5/eloquent-relationships#eager-loading p

The with function will accept a callback as the array value of the relationship key. You then have access to the underlaying query builder instance, I think this is what you want:
->with(['lastAppointment' => function($query) {
return $query->latest()->select('customer_id', 'start_at')
->groupBy('customer_id');
}])

Related

Laravel eloquent query with nested whereDate

I currently have a table called operators
The columns are:
id, user_id, item_clicked, created_at, updated_at
I can confirm on one of these it has today's update_at
2019-08-05 showing as today.
This is a relational table.
operators belongs to users.
I'm attempting to get operators of users whereDate is today.
My code is:
$ordersClicked = User::with('operators')
->whereDate('updated_at', \Carbon\Carbon::today())
->get();
This returns an empty array.
Testing this works so I know the data I need is there.
$ordersClicked = User::with('operators')
->get();
$operator = Operator::whereDate('updated_at', \Carbon\Carbon::today())->get();
Any idea what I'm doing wrong?
According to the docs https://carbon.nesbot.com/docs/ Carbon::today() returns Y-m-d H:i:s, if used like you are doing in a where clause and the database stores the value in Y-m-d format.
Why don't you try this:
$ordersClicked = User::with('operators')
->whereDate('updated_at', \Carbon\Carbon::today()->format('Y-m-d'))
->get();
if that doesn't work; then it is possible the eloquent is applying the where clause on updated_at on the User table, instead of Operator. Did you mean to do something like this:
$ordersClicked = User::with(['operators' => function($query) {
$query->where('updated_at', \Carbon\Carbon::today()->format('Y-m-d'))
}])->get();
i.e. filter on the eager loaded collection? if this is what you intended, what will happen is it will return all users and only some operators that has the updated_at matching the criteria will have values, where others will be null.
Wouldn't it be better to reverse the query? i.e. make sure Operator has a belongsTo relationship on User model and query the data like this:
$operator = Operator::whereDate('updated_at', \Carbon\Carbon::today())
->with('user')
->get();

Laravel eloquent with relation data (Eager Loading)

I have two database tables items and measurement_units - item has measurement unit.
Now the problem is I want to select a particular column from items and some column from measurement_unit. I want to use Eager loading
e.g.
$items_with_mu = Item::with("measurement_unit")->select(["item_name", "item_stock"])->first();
When accessing measurement_unit. It returns null. Without the select function it returns data(measurement_unit).
$items_with_mu->measurement_unit;
can anyone help me and sorry for my English.
Try this
Item::with(['measurement_unit' => function($q) {
$q->select('id','unit_column'); //specified measurement_unit column
}])
->select('id','measurement_unit_id','item_name')
->get();
If your laravel version is >=5.5 then you can write in a single line
Item::with('measurement_unit:id,unit_column')
->select('id','measurement_unit_id','item_name')
->get()
You have to select the primary column of the main model like below.
items_with_mu = Item::with("measurement_unit")->select(["item_name", "item_stock", "primary_key"])->first();

Provide extra condition in eager loading which includes comparing of two columns, laravel

I have tables students, profiles, subjects and pivot table profile_subject
-students---------{id,profile_id,year}
-profiles---------{id}
-profile_subject--{profile_id,subject_id,year}
-subjects---------{id}
I want to select a student with id 5, and eager load profile and subjects for the students year.
Something like this:
$student = Student::with('profile','profile.subjects')->find(5);
But I also have to insert the condition
->wherePivot('year','=','students.year')
there somewhere. How to do that?
This query will not do the job cos it will search for records which year is "students.year" literary
Use lazy eager loading. This code will not create any additional queries, it'll create the same amount of queries as with() would:
$student = Student::find(5);
$sudent->load(['profile', 'profile.subjects' => function ($q) use ($student) {
$q->wherePivot('year', $student->year);
}]);

Laravel Eloquent - How Do You Add a Where Condition to a Distantly Related Model Using the ORM?

I currently have the following:
Cars::with('cases')->with(['parts', 'parts.engines', 'parts.engines.metals'])
->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');
The above will list all rows in my cars table along with the metal associated with the engine in each of those cars. The metals table is related to the cars table through the parts and then the engines tables.
I've tried using:
Cars::with('cases')->whereHas(['parts', 'parts.engines', 'parts.engines.metals'], function($query){
$query->where('weight', '=', 45)
})->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');
But this errors out since whereHas() does not accept an array for its first parameter and I don't see a way to link to distant relationships with it.
How do I apply a WHERE conditional on a column in the metals table using the built-in ORM?
whereHas() only needs the name of the relationship for which you'd like to add the conditions. So, if you're trying to add the condition to the metals, you just need to restrict the parts.engines.metals relationship.
On a side note, when you eager load nested relationships, you don't need to also specify to load the intermediate relationship. That is, when you eager load parts.engines, you don't need to also eager load parts.
So, your query would look something like:
Cars::with(['cases', 'parts.engines.metals'])
->whereHas('parts.engines.metals', function($query) {
$query->where('weight', '=', 45)
})
->orderBy('car_name', 'DESC')
->orderBy('id', 'DESC');
This query will only retrieve cars that have a related metal with a weight of 45. Additionally, for those cars that are retrieved, it will also eager load all of the cases, parts, engines, and metals related to those cars.
I think you mean this:
Cars::with(['cases', 'parts', 'parts.engines', 'parts.engines.metals' => function($query){
$query->where('weight', '=', 45);
}])->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');

Laravel - When to use ->get()

I'm confused as to when ->get() in Laravel...
E.G. DB::table('users')->find(1) doesn't need ->get() to retrieve the results, neither does User::find(1)
The laravel docs say "...execute the query using the get or first method..."
I've read the Fluent Query Builder and Eloquent docs but don't understand when the usage of get() is required...
Thanks for the help
Since the find() function will always use the primary key for the table, the need for get() is not necessary. Because you can't narrow your selection down and that's why it will always just try to get that record and return it.
But when you're using the Fluent Query Builder you can nest conditions as such:
$userQuery = DB::table('users');
$userQuery->where('email', '=', 'foo#bar.com');
$userQuery->or_where('email', '=', 'bar#foo.com');
This allows you to add conditions throughout your code until you actually want to fetch them, and then you would call the get() function.
// Done with building the query
$users = $userQuery->get();
For find(n), you retrieve a row based on the primary key which is 'n'.
For first(), you retrieve the first row among all rows that fit the where clauses.
For get(), you retrieve all the rows that fit the where clauses. (Please note that loops are required to access all the rows or you will get some errors).
find returns one row from the database and represent it as a fluent / eloquent object. e.g. SELECT * FROM users WHERE id = 3 is equivalent to DB::table('users')->find(3);
get returns an array of objects. e.g. SELECT * FROM users WHERE created_at > '2014-10-12' is equivalent to DB::table('users')->where('created_at', '>', '2014-10-12')->get() will return an array of objects containing users where the created at field is newer than 4014-10-12.
The get() method will give you all the values from the database that meet your parameters where as first() gets you just the first result. You use find() and findOrFail() when you are searching for a key. This is how I use them:
When I want all data from a table I use the all() method
Model::all();
When I want to find by the primary key:
Model::find(1)->first();
Or
Model::findOrFail(1)->first();
This will work if there is a row with a primary key of one. It should only retrieve one row so I use first() instead of get(). Remember if you deleted the row that used key 1, or don't have data in your table, your find(1) will fail.
When I am looking for specific data as in a where clause:
Model::where('field', '=', 'value')->get();
When I want only the first value of the data in the where clause.
Model::where('field', '=', 'value')->first();
Basically what you need to understand is that get() return a collection(note that one object can be in the collection but it still a collection) why first() returns the first object from the result of the query(that is it returns an object)
#Take_away
Get() return a collection first() return an object
You can use get() method with latest() method to get the latest record that were recently added to your table
For example
$user=Student::latest()->get();
return all the data in descending order

Resources