How to found item in sql Array laravel - laravel

I am trying to find an item by id, but my column is a comma separated string(primaryCategory in below screenshot). I want to get this field in my result when query by any string (i.e. by 50,20,41 etc).
I know there could be options like whereIn, whereHas etc. but not able to find correct syntax. Please help me with this.

Using comma separated string is bad practice for that task, better to create a new table.
But for your structure this way with func FIND_IN_SET is suitable:
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_find-in-set
$categories = [1,2,3];
$queryParts = [];
foreach($categories as $category) {
$queryParts[] = 'FIND_IN_SET("' . $category . '", `primaryCategory`)';
}
$query = implode(' OR ', $queryParts);
$list = Model::whereRaw($query)->get();
UPD
Righ solution
Use *ToMany relation:
https://laravel.com/docs/8.x/eloquent-relationships#one-to-many
https://laravel.com/docs/8.x/eloquent-relationships#many-to-many
You have to create a new table: model_categories and put there model_id and category_id. Every model can have several categories and vise versa, and then you can use the standard laravel whereHas function to find models with special categories.

Related

Laravel select table fields by using variables

I want to fetch selected fields from my tables in laravel for that I assign my table fields in a variable. But always it gives me some database query error, here I added my code for that. This working fine when I use direct fields instead of them assign into a variable
$selectedfields = "'table1.*', 'table2.*','table3.column'"
$data = DB::table('table1')
->select($selectedfields)->get();
You can use DB:raw:
$selectedfields = 'table1.*, table2.*, table3.column';
$data = DB::table('table1')
->select(DB::raw($selectedfields))->get();
You might need to join table as well.
your query should be like this
$data = DB::table('table1')
->join('table2','table2.id','=','table1.id')
->join('table3','table3.id','=','table1.id')
->select('table1.*','table2.*','table3.*')->get();

Laravel Collection Filter By Multiple Concatenated Unique Fields

I have a model download which has two three properties. Those properties are 'id' , 'user_id' , 'file_id'.
Whenever a user downloads a file a download record is created.
I want to grab all downloads that have both a unique file_id and unique user_id.
How is this accomplished.
A collection might come from a relationship and needs filtering afterward. Below is a tested working solution in laravel 5.7 and most probably in later versions also:
$unique = $collection->unique(function ($item)
{
return $item['brand'] . $item['model'];
});
Here is an article about this: http://laravel.at.jeffsbox.eu/laravel-5-eloquent-collection-methods-unique
You can use the groupBy method.
$downloads = DB::table('downloads')
->groupBy('file_id')
->groupBy('user_id')
->get();
OR
You can use the distinct method.
$downloads = DB::table('downloads')->distinct()->get();

"Order by" when querying relation

I have a Project table and a pivot table "like_project" which has 2 columns : user_id and project_id, so users can like Projects
I'm trying to list all the Projects and order them by number of likes, by using the "has" method, like this :
$projects = Project::has('likes')->paginate(10);
the issue is that I don't know how to order by number of likes, I have a function on my Project model to count the number of likes for a project :
public function getTotalLikes(){
return sizeof($this->likes()->getRelatedIds()); //I could use $this->likes()->count()
}
Unless you want to write out a long SQL query to run an GROUP/ORDER BY command I'd just run the eloquent collection's sort method once you get the projects back.
$projects->sort(function($project) {
return $project->likes->count();
});
It depends on how your likes are stored exactly, but most straightforward way is simple join (suppose MySQL):
$projects = Project::join('like_project as lp', 'lp.project_id', '=', 'projects.id')
->groupBy('projects.id')
->orderByRaw('count(lp.project_id) desc')
->select('projects.*') // and if needed: DB::raw('count(lp.project_id) as likesCount')
->paginate(10);

How to average multiple columns using Eloquent?

I'm looking to get the average value across multiple columns on a related model, something like this:
$this->reviews()->avg('communication', 'friendliness')
Where communication and friendliness are an array of column names. However it appears the aggregate functions only support single column names, so I'm doing this:
$attributes = array('communication', 'friendliness');
$score = array();
foreach ($attributes as $attribute)
{
$score[] = $this->reviews()->avg($attribute);
}
return round(array_sum($score) / sizeof($attributes), 1);
Which results in multiple queries. Any suggestions for a best practice here?
Thanks
To avoid multiple queries you can use a raw database expression within Eloquent as shown below:
$averages = $this->reviews()
->select(DB::raw('avg(communication) c, avg(friendliness) f'))
->first();
echo $averages->c;
echo $averages->f;
Since the aggregate function name avg is recognized by all supported database by Laravel, this will not be a big deal.

Mulitple LIKE db query using associative array- but all from the same column name...?

I'm trying to query my database using CodeIgniter's active record class. I have a number of blog posts stored in a table. The query is for a search function, which will pull out all the posts that have certain categories assigned to them. So the 'category' column of the table will have a list of all the categories for that post in no particular order, separated by commas, like so: Politics, History, Sociology. etc.
If a user selects, say, Politics, and History, The titles of all the posts that have BOTH these categories should be returned.
So, the list of categories queried will be the array $cats. I thought this would work-
foreach ($cats as $cat){
$this->db->like('categories',$cat);
}
By Producing this:
$this->db->like ('categories','Politics');
$this->db->like ('categories','History');
(Which would produce- 'WHERE categories LIKE '%Politics%' AND categories LIKE '%History%')
But it doesn't work, it seems to only produce the first statement. The problem I guess is that the column name is the same for each of the chained queries. There doesn't seem to be anything in the CI user guide about this (http://codeigniter.com/user_guide/database/active_record.html) as they seem to assume that each chained statement is going to be for a different column name.
Of course it is not possible to use an associative array in one statement as it would have to contain duplicate keys- in this case every key would have to be 'categories'...
With regard to MySQL, I just ran the following query on my database and there were no issues.
SELECT *
FROM `TicketUpdates`
WHERE content LIKE '%update%'
AND content LIKE '%footprints%';
Likewise the following code ran as expected:
$this->db->select('*');
$this->db->from('TicketUpdates');
$this->db->like('content', 'update');
$this->db->like('content', 'footprints');
print_r($this->db->get()->result());
If you're using the 'like' function in CI, you have to prefix and postfix them with the proper query functions, example:
$this->db->select('*');
$this->db->from('tablename');
foreach($cats as $cat){
$this->db->like('categories', $cat);
}
$result = $this->db->get();
you can use following code
$this->db->select("*")->from($table);
foreach($cats as $single_name)
$this->db->or_like("categories",$single_name);
$result = $this->db->get();

Resources