there is a lot of similar topics but couldn't find a solution for me. This query loads very slow.
public function getAllBids()
{
return Bid::with('user', 'group')
->join('auct_lots', function ($join) {
$join->on('bids.lot_id', '=', 'auct_lots.lot_id')
->where('auct_lots.company', 'LIKE', '%' . request('brand') . '%')
->where('auct_lots.model_name', 'LIKE', '%' . request('models') . '%')
->where('auct_lots.grade_en', 'LIKE', '%' . request('carGrade') . '%')
->where('auct_lots.auction_name', 'LIKE', '%' . request('auctions') . '%')
->where('auct_lots.model_type_en', 'LIKE', '%' . request('chassis') . '%')
->where('auct_lots.bid', 'LIKE', '%' . request('lots') . '%')
->where('auct_lots.lot_date', 'LIKE', '%' . request('date') . '%');
})
->orderBy('auct_lots.' . request('order_column'), request('order_type'))
->paginate(30);
}
I think the problem is that auct_lots has more than 40,000 records... But I'm not sure how to refactor this code to work faster.
When you are having large amount of data, it is better to use server side caching. This will improve performance very much faster.
Step 1: Create a Trait and write logic for store values in caching.
Ex:
trait Student{
public function storeStudentDataInCache(){
$students = Cache::rememberForever('studentList', function () {
return Student::
with(['class', 'exams'])
->where('is_published', 1)->orderBy('display_sequence', 'ASC')->get();
});
return $students;
}
}
Now in your controller call this method, this will return collection of data. So you do not need run sql queries all the time to get data. This method will run query only after one time. After that data will be stored in caching so it will get data's collection from caching text file.
Note: Whenever you update your data,please do not forget to delete this cache.
And you can also apply where condition for laravel collection or you can use filter method of collection to implement more filter logic.
Related
I have a Laravel Package where I filter Users that are fetched from the database with a User Eloquent Model. So I have something like
if ($request->get('search')) {
User::where('email', 'like', '%' . $search . '%')
->orWhere('first_name', 'like', '%' . $search . '%')
->orWhere('name', 'like', '%' . $search . '%')
...
Now I want to add ore preprocess some filters on the Users before this is done from the project itself. What first came to my mind is to fire an event like
event(new UserFilterStart($users));
where I modify Users before i run the filters. So the code would look like this:
$users = User::all();
event(new UserFilterStart($users));
if ($request->get('search')) {
$users->where('email', 'like', '%' . $search . '%')
->orWhere('first_name', 'like', '%' . $search . '%')
->orWhere('name', 'like', '%' . $search . '%')
I did not manage to hand over the variable by reference, so i can manipulate it. Which is probably a good thing, because then this might have been my final solution.
I get that it is not the way Events should be used and I am looking for alternatives. How can I achieve to inject/modify the code from the package? Considering that I own this package.
Ok, it turned out that it just works fine with the Event. I just made a mistake somewhere else. Are there any real shortcomings if I use Events like that?
I'm using SoftDeletesin my projects, which is recognized as deleted_at in database table, I want to search and find only deleted rows.
Here is my controller code
public function trashedJobSearch(Request $request)
{
$search = $request->get('search');
$jobs = Jobs::select('id', 'company_name', 'position_name', 'job_description','deleted_at', 'created_at', 'expire_date', 'status')
->where(DB::raw('lower(company_name)'), 'like', '%' . mb_strtolower($search) . '%')
->orWhere(DB::raw('lower(position_name)'), 'like', '%' . mb_strtolower($search) . '%')
->where('deleted_at', '!=', null)
->paginate(10);
return view('/trashed', compact('jobs'));
}
I tried to use onlyTrashed() but it's not working either.
As you have orWhere you need to use a grouping and also onlyTrashed
Jobs::select('id', 'company_name', 'position_name', 'job_description','deleted_at', 'created_at', 'expire_date', 'status')
->where(function ($query) use ($search) {
$query->where(DB::raw('lower(company_name)'), 'like', '%' . mb_strtolower($search) . '%')
->orWhere(DB::raw('lower(position_name)'), 'like', '%' . mb_strtolower($search) . '%');
})->onlyTrashed()
->paginate(10);
The onlyTrashed() method should work for you. Docs for Laravel deleted entries. I have seen times where adding the raw select statement screws it up though.
Take out the extra bits with the select and DB::raw and then add them in after you have what you need. Start with the simplest:
$testOfDeletedOnlyJobs = Jobs::onlyTrashed()->get();
From here, add in the other parts of your query to see where and why it fails. If the above gives you nothing, perhaps there are no deleted records?
You can use
Model::onlyTrashed()->get();
Did you have looking for this post yet?
How to get all rows (soft deleted too) from a table in Laravel?
You can try this.
In your Model-
use Illuminate\Database\Eloquent\SoftDeletes;
class ModelName extends Model
{
use SoftDeletes;
}
To get only deleted rows
$search = $request->get('search');
$data = App\ModelName::onlyTrashed()
->where('id', $search)
->get();
I have a query like so
$data = City::with('hotel')->orwherehas('hotel', function ($query) use ($user_input) {
//here i want to limit this result to 5
$query->where('name', 'LIKE', '%' . $user_input . '%')->take(5);
// $query->take(5); i have tried this too
})->orWhere('name', 'LIKE', '%' . $user_input . '%')->get();
inside the whereHas clause, I have a query that I want to limit to 5, now I tried limit, take but no luck after that where nothing is working I don't know why
You can pass your query to the ->with() query builder method:
$data = City::with(['hotel' => function($query) use ($user_input) {
$query->where('name', 'LIKE', '%' . $user_input . '%')->limit(5);
}])
->where('name', 'LIKE', '%' . $user_input . '%')
->get();
This will get all hotels associated with a city which have the user input, where the city contains the user input.
Note that the ->orWhere() is not used here.
What I'm trying to do is setup a server side configuration for a table data. So I have a model CounterLog that has 3 relationships set [belongsTo] category, location, user. I want a query to filter all CounterLog data including relationships, with offset, limit and orderBy methods set and in the same time retrieve all the filtered rows ignoring offset and limit. Here is what I managed until now and maybe understand better what I want:
$search_query = function($q) use ($search) {
$q->where('name', 'like', '%' . $search . '%');
};
$query = CounterLog::where('created_at', 'like', '%' . $search . '%')
->orWhereHas('category', $search_query)
->orWhereHas('location', $search_query)
->orWhereHas('user', $search_query);
$logs = $query->offset($offset)->limit($limit)->get();
$logs_total = $query->offset(0)->count();
In the last line I'm using $query->offset(0) because for some reason if offset is set to a number $logs_total becomes 0. I'm not sure this is the proper way to do it.. but even like this I have no idea how to use orderBy for ex. category.name.
I know I can always use raw queries in eloquent but I want to know if there is a way to use ORM and relationships. I would really appreciate if you could help me with this..cuz the struggle is real.
Thanks a lot :)
Apparently I haven't got a solution with ORM so I did it with "raw" queries:
$query = $this->db->table('counter_logs')
->leftJoin('categories', 'counter_logs.category_id', '=', 'categories.id')
->leftJoin('locations', 'counter_logs.location_id', '=', 'locations.id')
->leftJoin('users', 'counter_logs.user_id', '=', 'users.id');
->where('counter_logs.created_at', 'like', '%' . $search . '%')
->orWhere('categories.name', 'like', '%' . $search . '%')
->orWhere('locations.name', 'like', '%' . $search . '%')
->orWhere('users.name', 'like', '%' . $search . '%');
->select('counter_logs.id as id', 'categories.name as category', 'locations.name as location', 'users.name as user', 'counter_logs.created_at as date');
$json['total'] = $query->count();
$logs = $query->offset($offset)->limit($limit)->orderBy($sort, $order)->get();
Try to swap statements:
$logs_total = $query->count();
$logs = $query->offset($offset)->limit($limit)->get();
Or clone base query, like this:
$total_count_query = clone $query;
$logs = $query->offset($offset)->limit($limit)->get();
$logs_total = $total_count_query->count();
I'm building up a filterable list with Laravel 5.0 and I'm crashing on following Problem.
I get the filter parameters from a HTML form and pass them to the Query Builder, but if a form input stays empty all rows of the table filtered by the other filters should be returned.
Example code:
$collection = Model::withTrashed()
->where('attr1', 'LIKE', \Request::input('attr1', '%'))
->where('attr2', 'LIKE', \Request::input('attr2', '%'))
->where('attr3', 'LIKE', \Request::input('attr3', '%'))
->get();
This seems to be most correct code for me, but it doesn't work as expected. Do you know a good solution for my Problem? I don't want to integrate a messy switch/case statement for proofing for existence and building the collection up manually. :(
Thanks for your help.
It seems that your problem is that you are always passing the filters to the query and you should only pass them if they are not empty.
Maybe somethig like this would work for you:
$results = Model::withTrashed();
if (\Request::input('attr1')) {
$results->where('attr1', 'LIKE', \Request::input('attr1', '%'));
}
if (\Request::input('attr2')) {
$results->where('attr2', 'LIKE', \Request::input('attr2', '%'))
}
if (\Request::input('attr3')) {
$results->where('attr3', 'LIKE', \Request::input('attr3', '%'))
}
$collection = $results->get();
You need to tweak your query a bit like this:
$collection = Model::withTrashed()
->where('attr1', 'LIKE', '%' . \Request::input('attr1') . '%')
->where('attr2', 'LIKE', '%' . \Request::input('attr2') . '%')
->where('attr3', 'LIKE', '%' . \Request::input('attr3') . '%')
->get();
This will make sure that the LIKE clause is still correct when an empty input parameter is sent.