I have the following models: CardBoard, User, UserPricingPlans, PricingPlanLimits
Note: Don't mind if there is something wrong with the models code.They are working fine.
CardBoard
class CardBoard extends Model{ public function user(){ return $this->belongsTo('Models\User','id_user'); } }
User
class User extends Model{ public function pricingPlans(){ return $this->hasMany('Models\UserPricingPlan','id_user'); } }
PricingPlan
class PricingPlan extends Model{ public function limits(){ return $this->hasOne('Models\PricingPlanLimits','id_pricing_plan','id_pricing_plan'); } }
PricingPlanLimits
I'll not describe that Model, its not necessary for the problem. But keep in mind that there is an attribute called maxBoards.
The problem is that I only have the CardBoard Model Instance to work on and I want to get the maxBoard attribute from PricingPlanLImits. So I did it like this:
Note: I Already have the CardBoard Model Instance here!
$maxBoard = $cardBoard->user->pricingPlans->last()->limits->maxBoard; return $maxBoard;
The code above runs great, but the number of queries generated by this operation is an overhead to me. Eloquent do an SELECT for every Relationship called and I don't want all these data and operations.
{ "query": "select * from `users` where `users`.`id_user` = ? limit 1", "bindings": [ ], "time": 0.96 } { "query": "select * from `users_princing_plan` where `users_princing_plan`.`id_user` = ? and `users_princing_plan`.`id_user` is not null", "bindings": [ ], "time": 0.8 } { "query": "select * from `pricing_plan_limits` where `pricing_plan_limits`.`id_pricing_plan` = ? and `pricing_plan_limits`.`id_pricing_plan` is not null limit 1", "bindings": [ ], "time": 0.88 }
Isn't there an way to optmize this and run fewer queries in a Eloquent-Way ?
3 Answers
Answers 1
you can get a data in one query if you use with() method.
for example: CardBoard::with('user.pricingPlans')->get();
so can optimize your query using with
method.
Answers 2
Previous comments were not too relevant to this solution...
example
$cardboard->user()->whereHas('pricingPlans', function ($plans) { $plans->selectRaw('price_plan_limits.id, MAX(price_plan_limits.maxBoard) as MB')) ->from('price_plan_limits') ->where('price_plan_limits.id', 'price_plan.id') ->orderBy('MB', 'DESC') })->get();
Answers 3
I usually go in reverse order:
$maxBoard = PricingPlanLimits::whereHas(function($q)use($cardBoard){ $q->whereHas('PricingPlan', function($q1)use($cardBoard){ $q1->whereHas('User', function($q2)use($cardBoard){ $q2->whereHas('CardBoard', function($q3)use($cardBoard){ $q3->where('id', $cardBoard['id']); }); }); // Probably you have to improve this logic // It is meant to select select the last occurrence $q1->orderBy('created_at', 'desc'); $q1->limit(1); }); })->first()['maxBoard'];
Totally untested, but this should be the correct approach to achieve your goal in one query.
0 comments:
Post a Comment