Optimising Laravel query - php

Picked up Laravel recently for an API project and have got it all set up and working, and Ive been migrating an API written from a php function with a concatenated SQL string into Laravel query builder, all is fine apart from one part.
I have a table of stock, and a features table, so I have defined a hasMany relationship on the model of stock to the features, and when I pass in a string array of features to the query I need to loop over each feature and then get back all the stock items that have those features.
Using a whereIn is not what I need as that will give me stock that has only one of the features. If I use a standard where that will give me 0 results as soon as multiple features are added.
I have achieved what I want with the following code, but its terribly slow to execute but I am unsure of a better way to get the same result:
foreach($value as $v){
$builder->whereHas('features', function($query) use ($v) {
$query->where('code', $v);
);
}

Use query builder instead of Eloquent to optimize queries...
For example:
DB::table('stock')->join('features',function($join){
$join->on('features.id','=','stock.feature_id')
->where('code', $v);
})
->select('') <--- also select columns here..
->get();
Docs: https://laravel.com/docs/5.7/queries

Related

Show countif mysql query table to html

I have a countif query in mysql and I would like to show the table on my html. I'm currently using laravel 6.0 framework.
Here is the picture of the table i want to show:
Here is my code in html:
Here is my code in the controller:
There should be numerous errors with index function in your controller. Specifically with how you are trying to assign $count a value. Read these: Eloquent Methods all() vs get(), Eloquent Selects, Eloquent Ordering, Grouping, Limit and Offset, Eloquent Where.
Laravel has an excellent documentation, if you were to follow it - working with Laravel would become much easier.

Get data from one table using one query and filter different rows into separate variables (Laravel 5.1)

I understand the question might not be very clear but here is my situation. I'm using laravel 5 and i'm developing a CRM system. I have placed Marital Status and Sex/Gender into one Lookup table. Whenever i get the values from the database and pass it to the view, i have two separate queries.
$sexes = DB::table('Lookups')
->where('ValueType', '=', 'Sex')->get();`
$marstatus = DB::table('Lookups')
->where('ValueType', '=', 'Marital Status')->get();`
return view('clients.edit',compact('client'))
->with('sexes', $sexes)
->with('marstatus ', $marstatus );
This code actually works and i am able to get both the marital status and sex/gender on my view.
So, here is my question
Doesn't this mean that i am sending a query to the database twice which affects performance even if it is small
Isn't there a way to query all the values from the lookup table in one query and filter out the values on the controller. So it can be something like
$Lookups = DB::table('Lookups')
and then filter the $Lookups variable and assign it into two different variables ($sexes and $marstatus) based on my filter criteria. i.e ($sexes is for values that have ValueType = 'Sex' ...)
Which one is better for performance. Sending a query twice or three times or just filtering the data on the controller.
1) Yes it does. Just install Laravel Debugbar and see it yourself. It's a very handy tool strongly recommended.
2) Yes you can do that, laravel has nice helper functions for that type of needs:
$collection = collect(DB::table('Lookups')
->whereIn('ValueType', ['Marital Status', 'Sex'])
->get());
$marstatus = $collection->filter(function($item) {
return $item->ValueType == 'Marital Status';
});
$sexes = $collection->filter(function($item) {
return $item->ValueType == 'Sexes';
});
What this does is, it converts the result array to a Laravel Collection so that you can use the filter function. You can also use array_filter function to filter without converting the result array to a collection.
3) Databases are always one of the primary bottlenecks, the fewer the query number the better. However this should not be a general rule especially when cache is used. And for example making joins or subqueries to reduce the number of queries would be deadly mistake on some cases.
Performance is a huge subject. I'd recommend you to start with the Laravel Debugbar to compare the memory usage, number of queries etc. and investigate more on various techniques including cacheing and design patterns too. Accessing the tables directly within the controller is not a very good idea in the first place...
Yes it does mean that. How big is your Lookups table?
You probably mean $lookups = DB::table('Lookups')->all(); or perhaps consider using an Eloquent model class instead, e.g. $lookups = Lookup::all(); Perhaps you may want to cache the result if the table is small? e.g. use the Cache classes in Laravel.
Better for performance would be to use the cache.
It is belong to your query Data I mean your lookups table data.
You can write the query like this in one time:
$sexes_marital_status= DB::table('Lookups')->where('ValueType', '=', 'Sex')
->orWhere('ValueType' '=', 'Marital Status' )
->get();
return view('clients.edit',compact('client'))
->with('sexes_marital_status',$sexes_marital_status);
and this is better that you send your query in one time.
`

how to add sub query in yii when subquery return array

I an working on an API, in which I have 2 tables 1 for library and 2nd for issued books. We can issue 5 books to any user. I am working on an API in which I need to check if any user already assigned a book then he same book will not issue to him. I used a sub query for it. but it returns an array. So I can't get the data according my need. I need that if We issue 3 book to him than the books will show in other color. my code is:
$data1=(new \yii\db\Query())->select('book_id')->distinct()->from('issuedBooks')
->where('user_id=:user_id', [':user_id'=>310])->all();
$workout= (new \yii\db\Query())->select('*')->from('library')
->leftJoin(['issuedBooks'=>$data1],'issuedBooks.book_id=library.book_id')
->all();
$data1 return an array so my second query not working properly.
Preface: I know nothing of Yii Query Builder. But I do know SQL. And usually if you want to pass parameterized queries from an array you would list out the items of array with OR or IN() using the WHERE clause not JOIN.
Using above link, consider removing the joins and using a where clause in second query, passing the array, $data1 as a parameter:
->where(array('in', 'book_id', $data1))

Cakephp - get database data from not associated models

I wanted to ask, how can i get data from one table and use this in other find.
For example, i have films table.
I want to get highest rated 3 films. Result should return 3 ID's.
Now, i want to create other query from not associated table, and pass this 3 ID's as "conditions" to find data in other table.
I dont want to use associations, because, data is stored in many databases, and this is problematic.
Thank You.
Once you've got your film IDs you can use in to filter the results from your other Model:-
$filmIds = ['32','55','75'];
$query = TableRegistry::get('Model')->find()
->where(function ($exp, $q) use ($filmIds) {
return $exp->in('film_id', $filmIds);
});
// WHERE film_id IN ('32','55','75')
Check out the docs section on advanced conditions.
If you need to get your film IDs into the correct format (i.e. that shown in the example code) you can use Hash::extract() on the results from your previous query.
if your cakephp version 3.x you can use subqueries in fairly intuitive way
$films = TableRegistry::get('Films')->find('highestRated')
->select(['id'])
->limlt(3);
$query = $related->find()
->where(['id' => $films]);
Subqueries are accepted anywhere a query expression can be used. For example, in the select() and join() methods. http://book.cakephp.org/3.0/en/orm/query-builder.html#subqueries

Laravel - Full Text Search on Multiple Tables

I am using Laravel 4 and the Eloquent model for a project we are working on.
The database conforms to 3NF and everything works great. Also all MySQL tables were switched back from InnoDB to MyISAM since the MySQL version < 5.6 (full text search in InnoDB is only supported from 5.6 and up).
While creating some database search filters I am finding some shortage with using the Eloquent model vs the Query Builder. In specifics, especially when trying to do a full text search on columns from multiple tables (and staying within the Eloquent's object context).
For simplicity, we have the following database structure:
--projects
--id
--name
--status
--...
--users
--id
--...
--roles
--id
--project_id
--user_id
--...
--notes
--id
--project_id
--user_id
--note
--....
The following code (simplified and minimized for the question) currently works fine, but the full text search only works for one table (projects table).
if (Request::isMethod('post'))
{
$filters = array('type_id','status','division','date_of_activation','date_of_closure');
foreach ($filters as $filter) {
$value = Input::get($filter);
if (!empty($value) && $value != -1) {//-1 is the value of 'ALL' option
$projects->where($filter,'=',$value);
}
}
$search = Input::get('search');
if (!empty($search)) {
$projects->whereRAW("MATCH(name,description) AGAINST(? IN BOOLEAN MODE)",array($search));
}
}
// more code here...
// some more filters...
// and at the end I am committing the search by using paginate(10)
return View::make('pages/projects/listView',
array(
"projects" => $projects->paginate(10)
)
);
I need to extend the full text search to include the following columns - projects.name,projects.description and notes.note.
When trying to find how to make it with Eloquent we keep on coming back to Query Builder and running a custom query, which will work fine but then we will face these problems/cons:
Query Builder returns an array while Eloquent returns model objects. Since we are extending each model to include methods, we really don't want to give up the awesomeness of the Eloquent model. And we really don't want to use the Eloquent Project::find($id) on the return results just to get the object again.
We are chaining the 'where' methods to have any number of filters
assigned to it as well as for code re-usability. Seems like mixing
Eloquent and Query Builder statement together will break our chaining.
For the consistency of this project, we want all database queries to
stay in Eloquent connotation.
Reading Laravel's documentation and API, I could not find a method to run raw SQL queries using Eloquent. There is whereRAW() but it is not broad enough. I assume that this is a restriction made by design, but it is still a restriction.
So my questions are:
Is it possible to run a full text search on columns from multiple tables, only in Eloquent. Every piece of information I came across online, mentions using Query Builder.
If not, is it possible to use Query Builder searches and returning Eloquent objects? (without the need to run Project::find($id) on the array results).
And lastly, is it possible to chain Eloquent and Query Builder where methods together, while only committing using get() or paginate(10) at a later point.
I understand that Eloquent and Query Builder are different creatures. But if mixing both was possible, or using Eloquent to run raw SQL queries, I believe that the Eloquent model will become much more robust. Using only Query Builder seems to me a bit like under-using the Laravel framework.
Hope to get some insights about this since it seems as the forums/community of Laravel is still evolving, even though I find it to be an amazing framework!
Thanks and I appreciate any input you may have :)
First of all you can use query scope in your model/s
public function scopeSearch($query, $q)
{
$match = "MATCH(`name`, `description`) AGAINST (?)";
return $query->whereRaw($match, array($q))
->orderByRaw($match.' DESC', array($q));
}
this way you can get "eloquent collection" as return
$projects = Project::search(Input::get('search'))->get();
then, to search also into notes you can make a more complex scope that join notes and search there.
Not sure if this will help but there is a workaround in innoDB(in versions that support fulltext search), maybe it works for you.
Lets use 'notes' as second table
SELECT MATCH(name,description) AGAINST(? IN BOOLEAN MODE),
MATCH(notes.note) AGAINST(? IN BOOLEAN MODE)
FROM ...
.
WHERE
MATCH(name,description) AGAINST(?) OR
MATCH(notes.note) AGAINST(?)

Categories