How to groupBy() Eloquent collection by column? - php

I have a program table that refers to location, major, grade, type table. I want to group programs based on their location to major and type collection. I can group them by garde_id, but I want to have a grade name instead of grade id.
$programs = Program::whereLocation_id($location->id)
->with('location', 'department', 'major', 'grade')
->latest()->get();
$programs->groupBy('grade_id');
Result
[
1 => ['department-name','major-name','title'],
2 => ['department-name','major-name','title']
]
Expected
[
'phd' => ['department-name','major-name','title'],
'M.S' => ['department-name','major-name','title']
]
What is the best query to accomplish this in Eloquent?

Another solution for your case would be:
$grouped = $programs->groupBy(function ($item, $key) {
return $item['grade']->name; // Setting grade name as key
});

You can retrieve programs from grades and you'll have the expected result.
I guess the relationship name in Grade model is called 'programs'
$locationId = $location->id;
$grades = Grade::whereHas('programs', function($query) use ($locationId) {
$query->where('location_id', $locationId);
})->with(['programs' => function ($query) use ($locationId) {
$query->where('location_id', $locationId);
$query->with('location','department','major');
return $query;
}])->get();
You will have a collection of grades which each have their programs in it.
You can also group by grades name:
$grades->groupBy('name');

Related

Laravel Eloquent query siblings in same table with eager loading

I have a parent table called patients which has a one-to-many relationship with a child table called notes. (i.e. One patient can have several notes). If given a note, I would like to find other notes for the same patient. Notes are related to patients by a fk called patient_id.
In SQL, I'd do this:
SELECT * FROM notes WHERE patient_id={note.patient_id} AND id <> {note.id}
In Eloquent, I have this:
class Note extends Model
{
public function otherEncounterNotes()
{
return $this->hasMany('App\Note', 'patient_id', 'patient_id')->where('id', '<>',$this->id);
}
...
In my database, the patient with id=1 has two notes with ids 1 and 2, so if I look for the siblings of note id 1, I should get note id 2.
When I use find(), it works as expected, but when I use where(), it returns the original note instead of the sibling. Any ideas?
>>> Note::find(1)->otherEncounterNotes->pluck('id')
=> Illuminate\Support\Collection {#5542
all: [
2,
],
}
>>> Note::where('id',1)->with('otherEncounterNotes')->pluck('id')
=> Illuminate\Support\Collection {#5526
all: [
1,
],
}
Given a Note id, you could obtain the results you want by using the relationship with the Patient model.
$note_id = 1;
// "Pretty" syntax, but it's 3 queries
$sibling_notes = Note::find($note_id) // Query 1
->patient // Query 2
->notes()->where('id', '<>', $note_id)->pluck('id'); // Query 3
Or using a subquery
$note_id = 1;
// A bit messier, 1 query + 1 subquery
$sibling_notes = Note::where('id', '<>', $note_id)
->where('patient_id', function ($subquery) use ($note_id) {
$subquery->select('patient_id')->from('notes')->where('id', $note_id)->limit(1);
})
->pluck('id');
// PHP >= 7.4
Note::where('id', '<>', $note_id)
->where('patient_id', fn($q) => $q->select('patient_id')->from('notes')->where('id', $note_id)->limit(1))
->pluck('id');
The later, you could turn into a query scope
# Note model
public function scopeSiblingsOf($query, $note_id)
{
return $query->where('id', '<>', $note_id)
->where('patient_id', function ($subquery) use ($note_id) {
$subquery->select('patient_id')
->from('notes')
->where('id', $note_id)
->limit(1);
});
}
# Usage
Note::siblingsOf(1)->pluck('id');

Problem with fetching data from database in one to many polymorphic relations in Laravel

I have one to many polymorphic relationship in Laravel and I am trying to fetch data using eloquent query. I have Favorite model with favorites table
id user_id favoritable_id favoritable_type
1 17 1 App\Models\ProfileImage
2 10 1 App\Models\PostVideo this is some other model
and profile_images table with
id user_profile_id title path
1 17 etc etc
I need to fetch all profile_images from profile_images table that correspond to data in favorites table. So id from profile_images to match favoritable_id, user_profile_id to matches user_id and favoritable_type to match App\Models\ProfileImage from favorites table. Any help is appreciated. Here is my code.
Controller
public function getProfileImages()
{
$profileimage = ProfileImage::whereColumn('id', 'favoritable_id')->first();
// I AM BASICALLY STUCK HERE WITH $profileimage !!!
$favoriteProfileImages = $profileimage->favorites()->where([
'user_id' => auth()->id(),
'favoritable_id' => $profileimage->id,
'favoritable_type' => ProfileImage::class
])->get();
return $favoriteProfileImages;
}
Option 1
Assuming that there is no relation between User and Favorite models, get all the PostImage records which have an entry in favorites table for the currently logged in user.
$profileImages = Favorite::where('user_id', auth()->id())
->with([
'favoritable' => fn($query) => $query->where('favoritable_type', ProfileImage::class)
])
->get()
->pluck('favoritable')
->flatten()
->all();
Option 2
Assuming that User hasMany Favorite records - hasMany relationship exists
class User extends Model
{
public function favorites()
{
return $this->hasMany(Favorite::class);
}
// ...rest of the class code
}
Get the results via the User model
$profileImages = User::with([
'favorites' =>
fn($query) => $query->where('favoritable_type', ProfileImage::class)->with('favoritable')
])
->where('id', auth()->id())
->first()
->favorites
->pluck('favoritable')
->flatten()
->all();

Laravel with([]) select only some columns of the relation

Edit
This question is unique because it poses unique problems such as:
relations within the with components. (items.product.stockManagement).
A large amount of components, this causes the accepted answers of the linked question to not apply.
Suppose you have a large with() like the following:
$order = Order::with([
'company',
'complaints',
'person',
'items',
'items.product',
'items.product.stockManagement',
'status',
])->findOrFail($id);
How can I then select with all their relations but specific columns for some of them?
$order = Order::with([
'company', // select only id,name, size
'complaints', // select only id, name , body
'person',
'items',
'items.product', // select only id, name , price
'items.product.stockManagement',
'status', // select only id
'items.product.media',
'items.product.mainProduct',
'items.product.mainProduct.media'
])->findOrFail($id);
Like this:
$order = Order::with([
'company:id,name,size',
'complaints:id,name,body',
'person',
'items',
'items.product:id,name,price',
'items.product.stockManagement',
'status:id',
'items.product.media',
'items.product.mainProduct',
'items.product.mainProduct.media'
])->findOrFail($id);
The documentation is very brief about the loading of specific columns (you even have to scroll down a bit to the heading that says "Eager Loading Specific Columns").
You may not always need every column from the relationships you are retrieving. For this reason, Eloquent allows you to specify which columns of the relationship you would like to retrieve:
$books = App\Book::with('author:id,name')->get();
Note:
When using this feature, you should always include the id column and any relevant foreign key columns in the list of columns you wish to retrieve.
You can also provide a callback for some more advanced relation querying.
Order::with([
'company' => function ($q) {
$q->select('id', 'name');
}
])
I faced the same problem. You need to specify the foreign id not id (primary key).
For example:
Data::with('other:id,name')->get();
It won't be working if you customize the foreign name.
So, you need to add your foreign column name completely.
Data::with('other:foreign_id,name')->get();
And that will work!
$order = Order::with(
['company' => function($query) {
$query->select('id','name','size')
}),
'complaints' => function($query) {
$query->select('id','name','body')
}),
'person',
'items',
'items.product' => function($query) {
$query->select('id','name','price')
}), 'items.product.stockManagement','status'=> function($query) {
$query->select('id')
}),'items.product.media', 'items.product.mainProduct', 'items.product.mainProduct.media'])->findOrFail($id);

How I can get distinct records from laravel table using elequent model?

I have to fetch distinct records based on the entity ID . I have tried this but it is not working
User::where('id',$id)->with(['userRoleEntity' => function($q) { $q->distinct('entityId'); }])->first();
I should get two records in the user entity array but I am getting 3. How I can fix this ? thanks in advance
the value in the square should not be there https://prnt.sc/qkamdi
distinct method not support to pass an parameter, you need to select a field and distinct
User::where('id',$id)->
with(['userRoleEntity' => function($q) {
$q->select('entityId')->distinct();
}])->first();
or
Try this one:
User::where('id',$id)->
with(['userRoleEntity' => function($q) {
$q->groupBy('entityId');
}])->first();

Laravel query a model in a nested query?

I have an Appointment model that has a relation to Employee and an Employee to a User. I am trying to query a list of appointments between specific dates ($weekStart and $weekEnd) and retrieve the appointments as well as the related Employees and Users.
So far this works, it returns all my Clients with all appointments and the assigned Employees/Users (Employees belong to User).
'clients' => Client::with('careType','appointments.employees.user')->get(),
However I wish to specify between dates on the appointments model. So I have this:
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}])->get(),
];
In the above what is the syntax to also retrieve the employees and user models when I have a sub query?
You just add your other models in your Client's with() array.
$data = [
'clients' => Client::with(['appointments' => function ($query) use ($weekStart, $weekEnd) {
$query->whereBetween('starts_at', [$weekStart, $weekEnd]);
}, 'appointments.employees.user'])->get(),
];

Categories