Laravel eloquont query takes long time to fetch data - laravel

I have a query just to retrieve the data, when I try to fetch 10k data from below query it will take more than 1.7mins. It that reasonable or how can I improve this time.
Vehicles::leftJoin('vehicle_details', 'vehicle_details.id', 'vehicles.vehi_details_id')
->leftJoin('vehicle_extras', 'vehicle_extras.vehicle_id','vehicles.id')
->leftJoin('reasons', 'reasons.vehicle_id', 'vehicles.id')
->leftJoin('revised_vehicles', 'revised_vehicles.vehicle_id','vehicles.id')
->leftJoin('makes', 'makes.model_id', 'vehicle_details.model_id')
->leftJoin('bidder_invoices', 'bidder_invoices.vehicle_id', '=', 'vehicles.id')
->leftJoin('bidding_views', 'bidding_views.vehicle_id', '=', 'vehicles.id')
->leftJoin('bidder_prs', 'bidder_prs.vehicle_id', '=', 'vehicles.id')
->leftJoin('bidder_remarks', 'bidder_remarks.vehicle_id', '=', 'vehicles.id')
->leftJoin('vehicle_pins', 'vehicle_pins.vehicle_id', '=', 'vehicles.id')
->leftJoin('translations', 'translations.vehicle_id', '=', 'vehicles.id')
->where(function ($query) {
$query->where('vehicles.approve', '=', 1)
->orWhereNull('vehicles.approve');
})
->orderBy('vehicles.site', 'ASC')
->orderBy('vehicles.auc_time', 'ASC')
->select([
'vehicles.*',
'vehicle_details.color as vehi_color',
'vehicle_details.grade as vehi_grade',
'vehicle_details.images',
'makes.model_name',
'vehicle_extras.id as extra_details_id',
'vehicle_extras.ic_remarks',
'vehicle_extras.bidder_adj',
'reasons.fob_issue',
'reasons.fob_approve',
'reasons.decline_remark',
'reasons.tc_issue',
'reasons.fob_overruling_remark',
'bidder_invoices.invoice_name',
'bidding_views.reason as bidder_reason',
'bidder_prs.bidder_mb as bidder_mb',
'bidder_remarks.bidder_remarks as bidder_remarks_daily',
'revised_vehicles.old_mb_round',
'translations.assigned_translator'
])
->paginate(10000);
I have also added indexes for every join column. Also I have used MySQL as my DB

you can use the Eloquent relationships as methods in your Eloquent model classes refer Eloquent Relationship
if the relation is 1:1 use hasOne
if the relationship is 1:M use has Many
if the relationship is M:1 use belongs to
in your Vehicle model
for example
for 1:1
public function vehicleDetails() {
return $this->hasOne(VehicleDetail::class,'vehi_details_id','id');
}
for 1:M
public function VehicleExtras() {
return $this->hasMany(VehicleExtras::class,'id','vehicle_id');
}
for M:1
public function VehicleMakes() {
return $this->belongsTo(VehicleMakes::class,'model_id','model_id');
}
and after making all the relationship you can get the vehicle table with your filters as follows
$data['vehicles'] = Vehicles::whereNull('vehicles.deleted_at')
->where(function ($query) {
$query->where('vehicles.multiple_po', 0)
->orWhereNull('vehicles.multiple_po');
})
->where(function ($query) {
$query->where('vehicles.approve', '=', 1)
->orWhereNull('vehicles.approve');
})
->orderBy('vehicles.site', 'ASC')
->orderBy('vehicles.auc_time', 'ASC')
->paginate(10000);
then,
you can the vehicles in the blade as normal and if you needed to call the relationship table belongs to a certain id,
to get a description from vehicle details you can access as follows
$data['vehicles']->vehicleDetails->description
or to get the of a make of the vehicle from the makes table
$data['vehicles']->VehicleMakes->name

Related

Laravel Query Through Relationship

I am creating a search in laravel where customers can search for vehicles.
Table 1
Vehicle
VIN
PLATE
make_and_model_id
Table 2
Vehicle Makes and Models
id
make
model
Relationship in Table 1: Vehicle
public function vehicle_make_and_model_fk()
{
return $this->belongsTo('App\Models\VehicleMakeAndModel', 'vehicle_make_and_model_id');
}
So I am searching for VIN or Plate. That works fine.
I also am Searching for a Make and Model name which is a foreign key.
I pulled in the related table using with which works fine.
Now how to search through the columns of Make and Model Table?
if($request->ajax()) {
$search = $request->search_query;
$vehicles = Vehicle::with('vehicle_make_and_model_fk')
->where(function ($query) use ($search) {
$query->where('plate', 'LIKE', '%'.$search.'%')
->orWhere('vin', 'LIKE', '%'.$search.'%')
->orWhere('vehicle_make_and_models.make', 'LIKE', '%'.$search.'%');
})
->limit(5)
->get();
echo json_encode($vehicles);
exit;
}
To filter the relationship, you need to use a closure in your with()
For example:
$vehicles = Vehicle::query()
->with([
'vehicle_make_and_model_fk' => function ($query) use ($search) {
$query->where('make', 'like', "%$search%")
->orWhere('model', 'like', "%$search%");
}
])
->where(function ($query) use ($search) {
$query->where('plate', 'like', "%$search%")
->orWhere('vin', 'like', "%$search%");
})
->limit(5)
->get();
Eloquent Relationships - Constraining Eager Loads
$vehicles = Vehicle::where('plate','LIKE','%'.$search.'%')
->orWhere('vin','LIKE','%'.$search.'%')
->with('vehicle_make_and_model_fk')
->orwhereHas('vehicle_make_and_model_fk',
function($query) use($search){
$query
->where('vehicle_make_and_models.make','like',$search.'%')
->orWhere('vehicle_make_and_models.model','LIKE','%'.$search.'%');
}
)
->limit(5)
->get();
This query worked. It would search and bring results from vehicle table and would go to makes and models table and bring results from there as well. Based on - Laravel Eloquent search inside related table

Laravel Query Item from table with selected relationships from another table

There are two tables which are related - Product and SalesForecast. I want to query products of a certain supplier with sales forecast from a period.
Relationships are established. My query is as follows:
$products = Product::where('supplier_id', $supplier)
->whereHas('stock_forecasts_fk', function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin);
$query->whereDate('date', '<', $end);
})
->get();
The relationship in the product model is as follows:
public function stock_forecasts_fk()
{
return $this->hasMany('App\Models\StockForecast');
}
This query does not work 100%. I want all products of that supplier to come (whether they have forecast or not). If they have a forecast, I need forecasts for that period only. Otherwise, that product will have not, forecast. But All product needs to come. Can someone advise how to fix this query so the result is as follows:
All products of suppliers come with relevant forecasts of between begin and end dates. If there is no forecast, then the product can come with no forecast.
You have to query with eager loading the relationship. with whereHas, only matching related value products will be collected. use with closure to query in related table
$products = Product::with(['stock_forecasts_fk' => function($query) {
$query->whereDate('date', '>', $begin)
->whereDate('date', '<', $end);
}])
->where('supplier_id', $supplier)
->get();
You can use with and pass a closure with your conditions to it:
$products = Product::where('supplier_id', $supplier)
->with(['stock_forecasts_fk' => function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin)
->whereDate('date', '<', $end);
}])
->get();
From the docs:
Constraining Eager Loads
Sometimes you may wish to eager load a relationship, but also specify
additional query conditions for the eager loading query. Here's an
example:
$users = App\Models\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
In this example, Eloquent will only eager load posts where the post's
title column contains the word first.
From the document that I've read here.
whereHas only includes Product which has stock_forecasts_fk, and discards Product which doesn't.
To select all product regardless it has stock_forecasts_fk, you should've use with.
$products = Product::where('supplier_id', $supplier)
->with([
'stock_forecasts_fk' => function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin);
$query->whereDate('date', '<', $end);
}
])
->get();

Laravel, where, orwhere in main table an pivot table

I have two tables with belongsToMany relation: message_topics and users
The pivot table is message_topics_users and contains 2 columns: message_id and user_id.
In table message_topics, I have a field called sender_id
I'm trying to write the correct eloquent syntax to get all the records:
where message_topics.sender_id = $user_id
OR Message_topics_users.receiver_id = $user_id
I tried many things, like for instance:
$topics = MessageTopic::where('sender_id', $user_id)
->wherePivot('receiver_id', $user_id)->orderBy('sent_at','desc')->get();
Any idea?
You can use the whereHas method (or in this case the orWhereHas method):
$topics = MessageTopic::where('sender_id', $user_id)
->orWhereHas('users', function ($query) use ($user_id) {
$query->where('id', $user_id);
})
->orderBy('sent_at', 'desc')
->get();
I'm assuming you have two relationships from the topics? Since it's too arbitrary to use both columns and the same relationship... Like this
//On your MessageTopic model
public function sender(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'sender_id');
}
public function receiver(){
return $this->belongsToMany('App\User', 'message_topics_users', 'message_id', 'receiver_id'));
}
Then you can use whereHas and orWhereHas like this:
//Again assuming you have your User model loaded as $user
$topics = App\Topic::whereHas('sender', function($q) use($user){
$q->where('sender_id', '=', $user->id);
})
->orWhereHas('receiver', function($q) use($user){
$q->where('receiver_id', '=', $user->id
})
->orderByDesc('sent_at')
->get();
whereHas and orWhereHas both query the model (MessageTopic in this case) checking for the existence of the specified relationship (App\Topic::whereHas('sender')...). They also allow you to pass the constraint that you're looking for (function($q) use($user){ $q->... })
So it is basically saying "Give me ONLY the MessageTopics that have a Sender or Receiver with the id $user->id"

Use Laravel Eloquent to query a minimum number of related models with the same attribute

It is not easy at all to explain the issue on a title so I'll try to explain with this example:
Tables/Models
Transaction (id, subscription_id, billing_date)
Subscription (id, user_id)
User (id)
A Transaction belongs to a Subscription;
A Subscription belongs to a User;
A User has many Subscription;
A Subscription has many Transaction;
I would like to retrieve all the transactions which are related to a subscription which is related to the same user, but only if there are two or more transactions with a billing_date == today.
Basically I want to know if there are transactions related to the same user which are going to be billed today. This is what I have now:
$transactions = Transaction::
whereHas('subscription', function ($query) {
$query->groupBy('subscriptions.user_id')
->havingRaw('COUNT(*) > 1');
})
->where('billing_date', '<=', Carbon::tomorrow())
->where('billing_date', '>=', Carbon::today())
->toSql();
and I also tried:
$transactions = Transaction::
whereHas('subscription', function ($query) {
$query->groupBy('subscriptions.user_id');
}, '>', 1)
->where('billing_date', '<=', Carbon::tomorrow())
->where('billing_date', '>=', Carbon::today())
->get();
I think that the second where clause is overrinding the first one, multiple where clauses can be passed as array :
->where([['billing_date', '<=', Carbon::tomorrow()]
,['billing_date', '>=', Carbon::today()]
])
->get();
I'm not sure this is the DRYest solution but you can make a second relation:
class Transaction {
public function currentSubscriptions() {
return $this->hasMany('App\Models\Subscription')
->where('billing_date', '<=', Carbon::tomorrow())
->where('billing_date', '>=', Carbon::today());
}
}
and then
$transactions = Transaction::has('currentSubscriptions', '>', 1)
->with('subscriptions')->get();

Excluding pivot rows in Eloquent ORM query

(laravel 4.2)
There are four tables involved; users, posts, flags, and post_flags.
I want to retrieve every post a certain user has, and retrieve the flags set for the post, but only the flags that are set by the user in question.
For example: A post can have flags: 1,2,2,3 where flag 2 is set twice. Once by User A, once by User B. I don't want to see the flags that User B has set.
The Eloquent query in my controller:
$posts = Post::whereHas('companies', function($q) use($company_id) {
$q->where('id', '=', $company_id);
})->with('flags')->get();
The Relation in my Post model:
public function flags() {
return $this->belongsToMany('PostFlag', 'post_postflags', 'post_id', 'flag_id')
->withTimestamps()->withPivot('owner');
}
How would I achieve this using Eloquent ORM?
UPDATE
My final query, thanks to andrewtweber:
Final query
$posts = Post::whereHas('users', function($q) use($id) {
$q->where('id', '=', $id);
})->get()->load([
'flags' => function($query) use($id) {
$query->where('owner', '=', $id)->orWhere('owner', '=', 'SYSTEM');
}
]);
Use wherePivot
http://laravel.com/api/4.2/Illuminate/Database/Eloquent/Relations/MorphToMany.html
$flags = $post->flags()
->wherePivot('user_id', '=', $user_id)
->get();
Or with eager loading
$posts->load([
'flags' => function ($query) use($user_id) {
$query->wherePivot('user_id', '=', $user_id);
}
]);

Resources