Using Laravel Eloquent to count how many times something exists in an efficient manner - laravel

I have a table called rentals, within each row are columns state,city,zipcode which all house ids to another table with that info. There are about 3400 rentals. I am pulling each column to display the states,city and zipcode distinctly. I need to show how many rentals are in each one. I am doing this now via ajax, the person starts typing in what they want to see and it auto completes it with the count, but its slow because of the way im doing it.
$rentals_count = Rentals::where('published',1)->get();
foreach($states as $state) {
echo $state.”-“.$rentals_count->where(‘state’,$state->id)->count();
}
Above is roughly what im doing with pieces removed because they are not related to this question. Is there a better way to do this? It lags a bit so the auto complete seems broken to a new user.

Have you considered Eager loading your eloquent query? Eager loading is used to reduce query operations. When querying, you may specify which relationships should be eager loaded using the with method:
$rental_counts = Rentals::where('published',1)->with('your_relation')->get();
You can read more about that in Laravel Documentation

$rentals = Rentals::wherePublished(true)->withCount('state')->get();
When you loop through $rentals, the result will be in $rental->state_count

Setup a relation 'state' on rentals then call it like this
$rentals_count = Rentals::where('published',1)->with('state')->get()->groupBy('state');
$rentals_count->map(function($v, $k){
echo $v[0]->state->name .' - '. $v->count();
});
Meanwhile in Rentals Model
public function state(){
return $this->hasOne(State::class, 'state'); //state being your foreign key on rentals table. The primary key has to be id on your states table
}

Related

Is it possible to fetch data using where clause with child relationship laravel

hope you all doing great.
I just moved to Laravel recently from CI.
I have two tables
- Bookings
- Booked_Rooms
What i want is if all the rooms are checked_out which i will decide by using Booked_Rooms.checkout_at is null then parent record should exclude from data set.
I tried google and did little bit research but couldn't find what i am actually looking.
I also tried Booking:with(array('rooms',function($q){ // where query })) but it is still fetching the parent record. I don't want to traverse every single record by loop and then excluding the records because it doesn't looks good for performance measurement. I also know that i can do this by using join but can i do this using Eloquent ORM
Summary : If all the checkout_at columns of all booked_rooms are not null then the parent booking record is considered as completed and shouldn't be in pending bookings.
HtlBooking Model Class
public function rooms()
{
return $this->hasMany('App\BookedRoom','booking_id');
}
Controller Function
$bookings = HtlBooking::with ( 'rooms' )->with ( 'user' )
->get ();
Found my answer, just did it by using
$bookings = HtlBooking::with('rooms')->whereHas('rooms',function($q){$q->where('checkout_at',null);})->with ( 'user' )
->get ();

Laravel 4.2 Sort by Eloquent Relationship Problems

I'm working with a datatable that I'm outputting from various relationships.
Most of the data comes from a meters table that has a Meter model, but some of it is pulled from other tables via relationships. For instance, I'm having an issue with sorting by the calibrations table.
The datatable has sortable columns that work just fine. The columns that sort based on other relationships have the joins in place so that they sort without any query errors.
All the sorting and joins work except for one, last_calibration_date.
There is no column called last_calibration_date. In fact, each meter could have multiple calibrations.
In the Meter model I grab the last_calibration_date from the calibrations table via the calibration_date column this way:
public function getLastCalibrationDateAttribute()
{
if (isset($this->relations['calibrations']) && $this->relations['calibrations']->count())
return $this->relations['calibrations']->sortBy('calibration_date', SORT_REGULAR, true)->first()->calibration_date->format('Y-m-d');
}
This works superbly when I'm not sorting by the last_calibration_date column, but returns a sql error if you try to sort by it without a join.
Here's my attempt at the join:
if ($sort == 'last_calibration_date')
{
$query->join('calibrations', 'calibrations.meter_id', '=', 'meters.id');
$sort = 'calibrations.calibration_date';
}
While this doesn't return an error it also doesn't return the actual last_calibration_date.
Just a little more info, the calibrations table is set up like so
calibrations
- id
- calibration_date
- next_calibration_date
- meter_id
So, as was said previously, any meter may have multiple calibrations.
Any ideas on how I could replicate my Meter method in my join? Or maybe another way of sorting by last_calibration_date?
Alrighty, well, I seem to have solved my problem without quite understanding why.
if ($sort == 'last_calibration_date')
{
$query->select('meters.*');
$query->join('calibrations as calibration', 'calibration.meter_id', '=', 'meters.id');
$sort = 'calibration.calibration_date';
}
Adding that $query->select('meters.*'); has solved it. Again, not sure why. My understanding is that is selecting a particular table's columns, not a model's relationships.
Anyways, it's working now.

Updating a pivot table in Eloquent

I've got a many to many relationship between a student and an institution_contact.
students should only ever have two institution_contacts and I have an attribute on the pivot table named type to be set as 1 or 2.
So, my pivot table looks like this:
institution_contact_student: id, institution_contact_id, student_id, type
I've run into difficulty in deciding how to approach the issue of adding/updating the pivot table. Let's say I have 100 students and I want to assign them a contact with the type of 1.
My current solution is to delete the contact then add it:
$students = Student::all(); // the 100 students
$contactId = InstitutionContact::first()->id; // the contact
foreach ($students as $student) {
// remove existing contact
$student
->institutionContacts()
->newPivotStatement()
->where('type', 1)
->delete();
// add new contact
$student
->institutionContacts()
->attach([$contactId => ['type' => 1]]);
}
However, I'm thinking that this is going to hit the database twice for each student, right? So would I be better off creating a model for the pivot table and removing all entries that matched the student id and the type then simply adding the new ones? Or would creating a model for the pivot table be considered bad practice and is there a better way of accomplishing this that I've missed?
Please note the reason I'm not using sync is because I'm relying on the type attribute to maintain only two contacts per student. I'm not aware of a way to modify an existing pivot without causing issues to my two contacts per student requirement.
Edit:
Instead of creating a model I could run the following code to perform the delete using DB.
DB::table('institution_contact_student') // the pivot table
->whereIn('student_id', $studentIds)
->where('type', 1)
->delete();
If I have understood your question correctly then you can use the updateExistingPivot method for updating your pivot table.But first of course you have to define the pivot in your relationship. For instance,
public function institutionContacts(){
return $this->belongsToMany('institutionContact')->withPivot('type');
}
after this, all you have to do is use the following code:
$student
->institutionContacts()
->updateExistingPivot($contactId, ["type" => 1]);
Hope this helps.

return separate result for each relation in many to many

Hi i have a many to many relationship with the following structure:
services
apps
service_app
I would like to have an eloquent query to return a separate result for each relationship(basically the pivot table). I have the following :
$all = App::with('services')->get();
this will return an app with nested services, I would like to have this return a separate result for each app-service combination along with data from the pivot table. how is this possible using eloquent?
It's a bit strange, but it can easily be done if you don't think of the pivot table as a pivot table, but as an AppService.
So what you can do is create a model for it, probably named AppService. In that model, you would then have 2 belongsTo() relationships. One for App and one for Service.
Then you can query your pivot table directly and use those relationships to get what you need.
$appServices = AppService::all();
foreach($appServices as $appService) {
echo $appService->app->description;
echo $appService->service->description;
}

Doctrine toarray does not convert relations

I followed doctrine documnetation to get started. Here is the documentation.
My code is
$User = Doctrine_Core::getTable("User")->find(1);
when I access relations by $User->Phonenumbers, it works. When I convert User object to array by using toArray() method, it does not convert relations to array. It simply display $User data.
Am I missing something?
By using the find method you've only retrieved the User data which is why the return of toArray is limited to that data. You need to specify the additional data to load, and the best place to do this is usually in the original query. From the example you linked to, add the select portion:
$q = Doctrine_Query::create()
->select('u.*, e.*, p.*') // Example only, select what you need, not *
->from('User u')
->leftJoin('u.Email e')
->leftJoin('u.Phonenumbers p')
->where('u.id = ?', 1);
Then when toArray'ing the results from that, you should see the associated email and phonenumber data as well.
I also noticed an anomaly with this where if you call the relationship first then call the ToArray, the relationship somehow gets included. what i mean is that, taking your own eg,
$User = Doctrine_Core::getTable("User")->find(1);
$num= $User->Phonenumbers->office; // assumed a field 'office' in your phone num table
$userArray = $user->toArray(true);
In the above case, $userArray somehow contains the whole relationship. if we remove the $num assignment it doesn't.
am guessing this is due to doctrine only fetching the one record first, and it's only when you try to access foreign key values that it fetches the other related tables

Resources