getting doubled queries laravel - php

I'm using laravel clockwork to monitor my queries
in my controller I have
public function index(){
$errorFound = false;
$error = ['error' => 'No Monitor Found'];
$urls = $this->url->with('url_status','latestUrlStatus','users');
if (request()->has('q')) {
$keyword = '%'.request()->get('q').'%';
$builder = $urls->where('description', 'like', $keyword);
$builder->count() ? $urls = $builder : $errorFound = true;
}
return $errorFound === false ? UrlsResource::collection($urls->latest()->paginate(5)->appends(request()->query())) : $error;
}
on my laravel clockwork im getting
doubled queries
is it normal? if it is a problem how can I fix this? TIA

There's no problem. All of those queries are expected.
The first query (select users...) isn't from the code you've shown. It came from TrustProxies.
The second query (select count()) is from $builder->count().
All the rest of the queries come from $urls->latest()->paginate(5). The first thing paginate() does is run a count() query (the third query) to get the total number of records. Then it moves on to call the real queries.
In this case, the fourth query is your main query for all your urls, the fifth query is the query to eager load your url_status relationship, the sixth query is the query to eager load your latestUrlStatus relationship, and the seventh query is the query to eager load your users relationship.

Related

Laravel query run twice

I am using Laravel spatie package for query builder and when I run my query it shows in the telescope that it runs twice the only difference between them is this line:
select
count(*) as aggregate
from
`accommodations`
where
.
.
.rest of my query
and the other one is like this :
select
*
from
`accommodations`
where
.
.
.
limit
10 offset 0
any idea what is wrong here because every one of those queries takes about 5 sec and that would be about 10 to 12 second extra for me. thanks
EDIT
$data = QueryBuilder::for(Accommodation::class)
->allowedFilters([
AllowedFilter::scope('bed_count'),
AllowedFilter::scope('filter_price'),
AllowedFilter::scope('filter_date'),
AllowedFilter::scope('discounts'),
AllowedFilter::exact('grade_stars'),
AllowedFilter::exact('city_id'),
AllowedFilter::exact('is_recommended'),
AllowedFilter::exact('accommodation_type_id'),
'name',
])
->allowedAppends(['cheapestroom'])
->allowedIncludes(['gallery','city','accommodationRooms','accommodationRooms.roomPricingHistorySearch','discounts','prices'])
->allowedSorts([
AllowedSort::custom('discount', new DiscountSort() ,'amount'),
AllowedSort::custom('price', new PriceSort() ,'price'),
])
->paginate(10);
this is my spatial query builder and this is the part that takes 5 secs twice :
class DiscountSort implements Sort
{
public function __invoke(Builder $query, bool $descending, string $property) : Builder
{
$direction = $descending ? 'DESC' : 'ASC';
$data = $query->join('accommodation_rooms', 'accommodations.id', '=', 'accommodation_rooms.accommodation_id')
->join('discounts', 'accommodation_rooms.id', '=', 'discounts.accommodation_room_id')
->select('accommodation_rooms.id')
->orderBy('discounts.amount', 'desc')
->select('discounts.amount', 'accommodations.*')
->groupBy('discounts.amount', 'accommodation_rooms.id')
;
return $data;
}
Its a join and because laravel and this package are not able to order data by relationship or nested relationship value I should have used a join.
Can that second query be the cause of pagination ??
It's in the paginate, the pagination needs to know how many records are in the full result, to display all the needed informations; therefor is the count query.
The second one gets the results for the current page of your pagination ;)

execute multiple quires at once in laravel

I need to execute 3 quires when user comes to main page.
public function index()
{
$slider = \App\Slider::select("title", "poster", "link", "sub_title")->translate()->orderBy("created_at", "asc")->get();
$services = \App\Page::getPage(24)->tabs()->translate()->get();
$partners = \App\Partner::select('id', 'title', 'link')->translate()->get();
return view('Front/index', compact('slider', 'services', 'partners'));
}
as you can see, I need to get images from slider, take page data and take some company partners info. so i execute 3 quires to get what i want. is there way to make only one query and union all these 3 quires in one? I want something like multi_query function in php. no matter it would be in eloquent or query builder.
p.s. I don't eloquent relationships, these data aren't related to each other
just put ur query inside $qry=DB::select("your_query");
return view('your_view',compact('qry'));
you can see following also for better unterstand
$emp_id="5623";
$var_start_date=$request->startdate;
$data_query= DB::select("SELECT orinfo.*,
chinfo.name as chname
FROM order_info orinfo, ch_info chinfo
WHERE orinfo.ch_id= chinfo.ch_id
AND orinfo.emp_id= ?
AND
to_char(orinfo.order_Date,'mm/dd/yyyy') BETWEEN ? AND ? order by orinfo.order_Date desc",[$emp_id,$var_start_date,$var_end_date]);

Eloquent HasMany relationship, with limited record count

I want to limit related records from
$categories = Category::with('exams')->get();
this will get me exams from all categories but what i would like is to get 5 exams from one category and for each category.
Category Model
public function Exams() {
return $this->hasMany('Exam');
}
Exam Model
public function category () {
return $this->belongsTo('Category');
}
I have tried couple of things but couldnt get it to work
First what i found is something like this
$categories = Category::with(['exams' => function($exams){
$exams->limit(5);
}])->get();
But the problem with this is it will only get me 5 records from all categories. Also i have tried to add limit to Category model
public function Exams() {
return $this->hasMany('Exam')->limit(5);
}
But this doesnt do anything and returns as tough it didnt have limit 5.
So is there a way i could do this with Eloquent or should i simply load everything (would like to pass on that) and use break with foreach?
There is no way to do this using Eloquent's eager loading. The options you have are:
Fetch categories with all examps and take only 5 exams for each of them:
$categories = Category::with('exams')->get()->map(function($category) {
$category->exams = $category->exams->take(5);
return $category;
});
It should be ok, as long as you do not have too much exam data in your database - "too much" will vary between projects, just best try and see if it's fast enough for you.
Fetch only categories and then fetch 5 exams for each of them with $category->exams. This will result in more queries being executed - one additional query per fetched category.
I just insert small logic inside it which is working for me.
$categories = Category::with('exams');
Step 1: I count the records which are coming in response
$totalRecordCount = $categories->count()
Step 2: Pass total count inside the with function
$categories->with([
'exams' => function($query) use($totalRecordCount){
$query->take(5*$totalRecordCount);
}
])
Step 3: Now you can retrieve the result as per requirement
$categories->get();

Laravel eager loading, count before getting the result

I know this is weird, but somehow I would like to know if it is possible, I am creating my own pagination, and I have been looking for eager loading with pagination but some say it is still not available.
//this query will get the record count
$qry_counter = LeadsModel::with('emails','contacts','create_by_name','sources');
//this query will get the data
$query = LeadsModel::with('emails','contacts','create_by_name','sources');
if(isset($inputs['page_no']) && isset($inputs['records_per_page']))
{
//setting pagination variables
$paginate_start_record = ($inputs['page_no'] - 1) * $inputs['records_per_page'];
//get the corresponding results based on the page and records per page
$query->skip($paginate_start_record)->take($inputs['records_per_page']);
}
//loop through condition
foreach($conditions as $condition)
{
$query->orWhere($condition[0],$condition[1],$condition[2]);
$qry_counter->orWhere($condition[0],$condition[1],$condition[2]);
}
$results_counter = $qry_counter->get()->count();
$results = $query->get();
Any advise on how to optimize this code? Will it be possible to get the total records count first and then it will also return the records based on the set with skip and take? Thanks in advance

Laravel 4.1 WhereIn w/ Many to Many Relation and Conditionals?

I am working on an application where part of it needs to search through a number of different fields on the same model with AND - AKA find age whereBetween $from and $to AND where gender is $gender. Where I am getting lost is this model has a many to many relationship with Category and I need to filter by category in the same query. I am trying to do this in one query because it needs to be pretty fast.
Here is what I have so far:
$categories = Input::get('categories');
$query = Program::with('categories')->whereIn('category', $categories)->query();
if ($ages = Input::get('ages')) {
$query->whereBetween('age',array($from,$to));
}
if ($gender = Input::get('gender')) {
$query->where('gender','like', $gender);
}
// Executes the query and fetches it's results
$programs = $query->get();
I have put this together from so many different sources that I would like to know if this even works, or if it is the most efficient method possible. There is of course a table programs, a table categories, and a table program_category with columns id, program_id, and category_id.
Thanks in advance for your help!
So, in the end figured it out:
$query = Program::whereHas('categories', function($q) use ($categories)
{
$q->whereIn('categories.id', $categories);
});
'categories' is the name of the relationship function on my Program model. $categories is my array of category ids. Thanks again for your help.
This will work if fields are available in the right table as you queried for and you may write it like this:
$categories = Input::get('categories');
$query = Program::with('categories')->whereIn('category', $categories);
// declare $from and $to if not available in the current scope
if ($ages = Input::get('ages')) $query->whereBetween('age', array($from,$to));
if ($gender = Input::get('gender')) $query->where('gender', $gender);
// Executes the query and fetches it's results
$programs = $query->get();

Categories