Laravel Backpack select2_from_ajax without Pagination - laravel

I'm using the Laravel Backpack (v4.0) Admin / Crud. I'm implementing the select2_from_ajax field on my users table. This field requires that you return a query using the paginate() method.
$results = User::where('email', 'LIKE', '%'.$search_term.'%')->paginate(10);
This works, but returns results very slow (10+ seconds). I feel that the paginate() method is what is causing this to take along time to render. If I perform the query directly on the database it takes less then 500ms to return. I have indexes on the email field so that is not what is causing the problem. The users table is ~300k rows.
Does anyone know of a way to alter this so that I can perform an exact match query like below? I don't need it to return multiple results.
$results = User::where('email', '=', $search_term)->first();

Related

Query database table using LIKE in Laravel

I am trying to query a table using where like :
Auth::user()
->friends
->where('friend.first_name','LIKE','%'.$firstName.'%')
->all()
The query does work properly without using the LIKE statement only when i add the LIKE keyword it doesn't return any results.
Using all() will work without the builder where() statement.
When grabbing data using the query, use get() instead:
Auth::user()->friends->where('something','LIKE','%'.$something.'%')->get()
I think you are confused between a laravel relation and a eloquent collection. First let me go straight to answer, you would have to do
Auth::user()
->friends()
->where('friend.first_name','LIKE','%'.$firstName.'%')
->get()
To explain what's wrong with your code, ->where('name', 'Like', '%something%') This is a query builder method. You have to use it on the query builder, or Before you actually retrieve the model / model collection.
Auth::user()->friends()
This would give you a relation Illuminate\Database\Eloquent\Relations\HasMany that you can apply where like on.
Auth::user()->friends
This will return you a Illuminate\Database\Eloquent\Collection. And yes, it is a collection, so you will have to use collection method. Take a look at the where method for collection. You can see it only support key => value pair. It does not support "LIKE"
The where method filters the collection by a given key / value pair:
If you want to use achieve a "Like" on collection, you can probably use the filter method, which support custom callback.
The filter method filters the collection using the given callback, keeping only those items that pass a given truth test:
To conclude, when you define a friends "HasMany" relation on User, you have two way to retrieve it.
If you want to apply additional query builder method, you need to use user->friends() which do not return you data, it return you a relation that you can use query builder method. Once you do user->friends, it get you a collection. You cannot apply query builder on that anymore. So basically, user->friends is act the same way as user->friends()->get()
Don't Use all() and use get().
Auth::user()->friends()->where('something','LIKE','%'.$something.'%')->get()

Trying to create a GROUP BY with eloquent

$collections = Collection::selectRaw("DATE(created_at) as collection_date, sum(gross_amount) as amount")
->groupBy('collection_date')
->paginate(10);
When I do that it displays that collection_date does not exist in the table, so I wonder how can I create a group by with just DATE() in eloquent?
Thanks
Based on Laravel docs, pagination doesn't work with the groupBy clause properly.
https://laravel.com/docs/7.x/pagination#paginating-query-builder-results
Currently, pagination operations that use a groupBy statement cannot be executed efficiently by Laravel. If you need to use a groupBy with a paginated result set, it is recommended that you query the database and create a paginator manually.

How to Paginate Multiple Models in Laravel without overworking the memory

Im trying to figure out the best way to paginate in laravel when i am working with big datasets, the method i am using now is overworking the memory. this is what i am doing: i query from multiple tables, map the results etc, then merge multiple collections, and only after that do i paginate it, i realized though that this is a really bad way of going about this, because i am querying way to much data for no reason, and as the data grows the slower it will become.
the question is what would be the correct way?
i thought maybe i would paginate and then work with the data, the issue is that for instance if i was trying to sort all the merged data by date i wouldn't be getting the proper results because one table may have less data then the other...
here is some of the code to help with clarifying the question
first i will query two tables orders table and transactions table
$transactions = Transaction::all();
$orders = Order::all();
then i will send this all to a action to map it all and format it the way i need to with laravel resources
return $history->execute(['transactions' => $transactions, 'orders' => $orders]);
what this action does is simply map all the transactions and return a resource, then it will map all the orders and return resources for them as well, after which it will merge it all and return the result.
then i take all of this and run it through a pagination action which uses the Illuminate\Pagination\LengthAwarePaginator class.
the results are exactly the way i want them its simply a memory overload.
i tried paginating first instead of doing
$transactions = Transaction::all();
$orders = Order::all();
i did
$transactions = Transaction::orderBy('created_at' 'desc' )->paginate($request->PerPage);
$orders = Order::orderBy('created_at' 'desc' )->paginate($request->PerPage);
and then run it through the action that returns resources.
there are a few issues doing this, firstly, i will no longer get back the pagination data so the app won't know the current page or how many records there are, secondly, if for example the orders table has 2 records, and the transactions table has 10 records, event though the dates of the orders table is after those of the transactions table they will still get queried first.
Use chunk method or paginate
Read documentation.

Laravel search result is too slow

I need to build search functionality in my website. So far I have implemented the query in eloquent. It is like this,
`$syukko = Syukko::where('category', $cat)
->where('status', 1)
->get();`
Now, this website may have a large database. My tester tested it and reported that, it was performing too slow. I tried to use paginate to show 20 results per page. Still the speed was not improving.
One colleague suggested me to use AJAX. My question is does AJAX search perform faster than basic eloquent in pgsql? (live search is not necessary)
Also, currently I don't have large database with my machine. I write the code and send it to tester. Can I use any tool to get query time in localhost?
Just using ajax won't increase the speed, you need to optimize your query and use it properly to improvise the speed. As #duy Said you can do the indexing to improve the speed.
Laravel Pagination: Default laravel pagination runs count query to get the total records, which might take time if you are querying a large database.
You might try a custom pagination will increase the speed.
function showSearchR(Request $request){
$page = (isset($request->page))?$request->page:1;
$limit = 20;
$offset = ($page-1)*$limit;
$syukko = Syukko::where('category', $cat)
->where('status', 1)
->offset($offset)->limit($limit)
->get();
}
To get the query time you can use laravel query log:
Enable the query log by DB::enableQueryLog(); then use this code after excuting a query dd(DB::getQueryLog())
In this case, you have to create database index on category and status in order to increase database performance.
Ajax cannot improve performance a lot, because finally you should use eloquent to access database and return the data.

Laravel not returning join query to blade

I have two queries, one is lighter on data by using the pivot table as a filter to get data from the main table (student in this case).
$students=\DB::table('student')->join('school_student', 'student.id', '=','school_student.student_id')->get();
This returns a query result from the controller. But will not load into the blade:
$this->layout->content=\View::make('admin.students.index')->with('student', $students);
Whereas this versions returns a similar more data heavy (i.e. outputs all school data each time)
but works in blade.
$students = \Student::with(array('schools' => function($query){$query->where('school_id', '=', 1);}))->get();
Is it simply that DB and view are incompatible?
If so what is the Laravel 4 method to query one table and it's pivot only.
Any help appreciated.
In the blade
#if($student->count())
The first example produces this error:
Call to a member function count() on a non-object
DB::...->get() returns an array, so you can't call ->count() on it (hence "non-object"), but instead you need count($students).
The reason ->count() works when you do the 'more data heavy' method is that you're using Eloquent and it returns Eloquent Collections.
So, basically, you're doing two different things and expecting to treat them the same.
Also, while I'm here I should point out that I think your Eloquent query isn't quite right. First off you're hardcoding the id as 1 (whereas in the DB-style query you don't care about the school ID, and you just use it to join to the pivot table - maybe you used an incomplete query), but also you're using with but you should probably look at has. with eager-loads models, but has is what you want if you just want to check for a condition on a join table.

Resources