I've seen similar questions about collections, but they don't quite fit my use case for a hasMany relationship
Context: In Laravel 8, via an api controller method, I'm trying to return Account->doctors:hasMany|Doctors with only three key value pairs rather than the entire model.
The goal is to make queries as efficient as possible via native laravel methods while keeping the api responses light.
What I've tried:
collection->pluckonly allows for one key, or a single key, value pair- I've seen
selectsuggested for similar problems, but it doesn't apply to collections
My current solution uses collection->map(model->only(['keys']))
only seems to be the weapon of choice for returning select key value pairs from a model, but only works differently on collections. In a collection, only seems to focus on which models to return, rather than which keys.
Calling map and then running only on the individual models does work, but it feels too verbose and makes me think I'm missing a (hopefully) more efficient native method elsewhere.
I don't know how eloquent handles it's queries, but from the syntax I'm using below it appears that map requires the full models to be queried before they can be changed and is therefor inefficient, but I realize I could be wrong about that.
return $account->doctors->map(function ($doctor) {
return $doctor->only(['ref_id', 'name', 'code']);
});
Is there a better method in this circumstance that can reduce syntax and increase the efficiency of the query?
CodePudding user response:
You can use map as a High Order function to make the syntax less verbose.
return $account->doctors->map(function ($doctor) {
return $doctor->only(['ref_id', 'name', 'code']);
});
becomes
return $account->doctors->map->only(['ref_id', 'name', 'code']);
This will not change the SQL query itself (SELECT * FROM doctors WHERE ...). If you want to change that part, you'll need to change the syntax or pass a Closure where place you eager load the relationship.
$account = Account::with('doctors:ref_id,name,code,account_id')->find($id);
$account = Account::with(['doctors' => function ($query) { $query->select('ref_id', 'name', 'code', 'account_id'); }])->find($id);
$account = Account::with(['doctors' => fn ($query) => $query->select('ref_id', 'name', 'code', 'account_id')])->find($id);
$account->load('doctors:ref_id,name,code,account_id');
$account->load(['doctors' => function ($query) { $query->select('ref_id', 'name', 'code', 'account_id'); }]);
$account->load(['doctors' => fn ($query) => $query->select('ref_id', 'name', 'code', 'account_id')]);
CodePudding user response:
From what I've understood from your question, you can make use of eager loading: https://laravel.com/docs/8.x/eloquent-relationships#eager-loading-specific-columns
Assuming you've instantiated a hasMany relationship function named doctors in Account Model, you can try something like this:
Account::with('doctors:id,ref_id,name,code')->where('your conditions')->get();
Keep in mind, you have to include the primary key of doctor (I assumed it is 'id' in this case) when you're trying to execute this.
