Laravel 9 - Eloquent group results of query - php

I am looking for a way to take one query in Eloquent to get all search results, and then take those results, group them by type, and output the different types.
I currently have this setup to get all my search results:
$listings = Listing::where('listings.expiration_date', $date_operator, date('Y-m-d H:i:s'));
$listing->where(function($query) use ($keyword) {
$query->where('listings.lot_number', 'LIKE', '%'.$keyword.'%')
->orWhere('listings.title', 'LIKE', '%'.$keyword.'%')
->orWhere('listings.brand', 'LIKE', '%'.$keyword.'%')
->orWhere('listings.grade', 'LIKE', '%'.$keyword.'%')
->orWhere('listings.tags', 'LIKE', '%'.$keyword.'%')
->orWhere('listings.player', 'LIKE', '%'.$keyword.'%');
})->leftJoin('bids', function($join){
$join->on('bids.listing_id', '=', 'listings.id')
->on('bids.id', '=', DB::raw("(select max(id) from bids WHERE bids.listing_id = listings.id)"));
})->leftJoin('media', function($join) {
$join->on('media.listing_id', '=', 'listings.lot_number')
->where('media.group_order', '=', '1')->groupBy('media.group');
});
$listings = $listings->get();
The resulting $listings shows all the search results that I want to appear. Each listing has a specific type (item_type) assigned to them (i.e. Card, Ball, Bat, etc). I'd like to take all those results and group the types so that I can get a unique list of types to display in the menu. I've tried GroupBy on the Collection but that doesn't seem to be working.
Thank You

Use the power of collections
$itemTypes = $listings->pluck('item_type')->unique()
// if item type is a sub array / relationship then you will need to use dot notation
So we are plucking only the 'item_type' field, removing all duplicates by using the unique method and you should then have a collection of unique item_type's

Related

Laravel: Using multiple search terms to get an entry

Right now, I am grabbing users who fit a certain criteria like this:
$searchTerm = 'MULTI';
$multiUser = USER::where('code', 'LIKE', '%'.$searchTerm.'%')->get();
Now I changed the code to be "MANY" but we have a lot of users who already have MULTI as their code so I need the searchTerm to grab both. Can I do this in one query?
User::query()
->where('code', 'LIKE', '%MULTI%')
->orWhere('code', 'LIKE', '%MANY%')
->get();

Laravel 5.4 Query Builder Implementing orderBy with groupBy

I wanted to manipulate how data will be shown with cost layering methods such as LIFO and FIFO.
To get things started, here's my query:
$items = Inventory::whereActive('1')
->where('quantity', '>', 0)
->where(function($query) use($request) {
$query->where('name', 'LIKE', '%'.$request->search.'%')
->orwhere('ref_code', 'LIKE', '%'.$request->search.'%');
})->orderBy('created_at', 'dsc')
->groupBy('ref_code')
->get();
I wanted to use groupBy with ref_code so it will only show one data with the same ref_code, and I used orderBy with created_at and dsc for descending so that one data that will be shown will be the last one that was added. (Well, that's what I think that would happen).
But unfortunately, when I used groupBy, it only shows the first added data. How can I select the last data? I thought orderBy was gonna do the job but it didn't.
You can use an alternative way for this. If you have auto incrementing primary key as id then you can do it like,
$ids = Inventory::whereActive('1')
->where('quantity', '>', 0)
->where(function($query) use($request) {
$query->where('name', 'LIKE', '%'.$request->search.'%')
->orwhere('ref_code', 'LIKE', '%'.$request->search.'%');
})
->select('ref_code',\DB::raw('MAX(id) as ID'))
->groupBy('ref_code')
->pluck('ID');
Now, Get Items as
$items = Inventory::whereIn('id',$ids)->get();
Hence you will get your desired result.

paginate merged collections (or: how to sort by presence of a string)

I originally had this solution for searching for a term:
Post::where('title', 'LIKE', '%'.$searched.'%')->orWhere('content', 'LIKE', '%'.$searched.'%')->paginate(100);
What I want:
I want the records containing a term in title to be on top of the colllection
My temporary solution:
Pretty obvious:
$posts1 = Post::where('title', 'LIKE', '%'.$searched.'%')->paginate(100);
$posts2 = Post::where('content', 'LIKE', '%'.$searched.'%')->paginate(100);
$object = $posts1->merge($posts2);
Problem to solve
The $object collection cannot be paginated. I get error Method hasPages does not exist..
Is there any way to keep the pagination function on the resulting (sorted & merged) collection?
Why not use
->orderByRaw()
them using
'(case when title LIKE "%'.$searched.'%" then 1 else 2 end) ASC'
in this cause those whose name contains $searched will be on the top
so your query builder would be like this
Post::where('title', 'LIKE', '%'.$searched.'%')
->orWhere('content', 'LIKE', '%'.$searched.'%')
->orderByRaw('(case when title LIKE "%'.$searched.'%" then 1 else 2 end) ASC')
->paginate(100);

Laravel - Query Model if values contain a certain string (taken from search input)

I am implementing a search using Laravel and Ajax. So I have a Product which belongs to a Tag and a Subcategory. On the other hand the Subcategory belongs to a Category. I want to check all of their properties (field values) and check if they contain the given string. With some searching I found out that I have to use LIKE. Here is what I tried:
$products = Product::where('name_en', 'LIKE', $search)->get();
However this will get the products if the search string matches exactly the value. I want to match if it contains it. How can I proceed with the belongsTo relationships? How can I check the propreties of Tag and Subcategory as well? How to chain everything together so I achieve the desired result? Thanks in advance.
you are doing one thing wrong, your query returns you exact matches because you given the exact string. But your query should be like this.
$products = Product::where('name_en', 'LIKE', '%'.$search.'%')->get();
Above query will gives your products which contains the searched string.
And if you want to search in relational tables then you can user laravel method join(). But there are one more method whereHas but I always avoiding this method, because it creates very complex query. which is very heavy. So you can use join() method which will add inner join with relational table.
Here is the example of join:
$products = Product::join('tags', function($builder) {
$builder->on('tags.id', '=', 'products.tag_id');
// here you can add more conditions on tags table.
})
join('sub_categories', function($builder) {
$builder->on('sub_categories.id', '=', 'products.tag_id');
// here you can add more conditions on subcategories table.
})
->where('name_en', 'LIKE', '%'.$search.'%')
->get();
This is the basic example, you can use this according to your requirement.
To add to Lakhwinder Singh’s answer, it might be worth wrapping it up in a scope that you can apply to your model:
class Product extends Model
{
public function scopeSearch($query, $keywords)
{
return $query->where('name_en', 'LIKE', '%'.$keywords.'%');
}
}
You can then use this scope like this:
$products = Product::search($keywords)->get();
Which means you don’t have to keep manually adding “LIKE” conditions throughout your application.
As an aside, Laravel’s introducing Scout, a driver-based full text search extension for Eloquent, in version 5.3.
What you want is to write an advanced query to search product based on related models too, so as previous suggestion by others, you have to write join statements.
Check my example code below, which is written to search members, the search string also will bring members if the string matches, members skills or positions, so this will surely help you.
$users = User::select('app_users.*')
->distinct()
->join('app_members', 'app_users.id', '=', 'app_members.app_users_id')
->leftJoin('app_members_jobtitles', 'app_members.id', '=', 'app_members_jobtitles.app_members_id')
->leftJoin('app_jobtitles', 'app_members_jobtitles.app_jobtitles_id', '=', 'app_jobtitles.id')
->leftJoin('app_members_tags', 'app_members.id', '=', 'app_members_tags.app_members_id')
->leftJoin('app_technologies', 'app_members_tags.app_technologies_id', '=', 'app_technologies.id')
->whereNull('app_users.activation')
->where('app_users.block','=',0)
->where(function ($query)use ($search) {
$query->orWhere('app_users.first_name', 'like', '%'.$search.'%')
->orWhere('app_users.last_name', 'like', '%'.$search.'%')
->orWhere('app_members.company', 'like', '%'.$search.'%')
->orWhere('app_members.job_title', 'like', '%'.$search.'%')
->orWhere('app_jobtitles.title', 'like', '%'.$search.'%')
->orWhere('app_technologies.title', 'like', '%'.$search.'%')
->orWhere('app_members.summary', 'like', '%'.$search.'%');
})
->get();
Note the following join in the above code, which is in your case category and sub category
->leftJoin('app_members_jobtitles', 'app_members.id', '=', 'app_members_jobtitles.app_members_id')
->leftJoin('app_jobtitles', 'app_members_jobtitles.app_jobtitles_id', '=', 'app_jobtitles.id')

Laravel Eloquent Search Multiple Related Tables

I am struggling with figuring out how to run a like query against multiple related tables.
I have a submissions table that has related users, mcd_forms, and submission_statuses tables.
Here is my code for running a LIKE statement with the given $terms_like.
$submission = new Submission;
$terms_like = '%'.$search_terms.'%';
$data['submissions'] = $submission
->join('users as users', 'users.id', '=', 'submissions.user_id')
->join('mcd_forms as forms', 'forms.submission_id', '=', 'submissions.id')
->join('submission_statuses as statuses', 'statuses.id', '=', 'submissions.submission_status_id')
->where(function($q) use ($terms_like) {
$q->where('users.user_group_id', '=', Auth::user()->user_group_id)
->orWhere('forms.name', 'like', $terms_like)
->orWhere('forms.custom_id', 'like', $terms_like)
->orWhere('forms.start_date', 'like', $terms_like)
->orWhere('forms.end_date', 'like', $terms_like)
->orWhere('forms.soft_sell_date', 'like', $terms_like)
->orWhere('forms.region', 'like', $terms_like)
->orWhere('statuses.status_formatted', 'like', $terms_like);
});
No matter what I try it returns incorrect results. What am I doing wrong?
In your query above, since you are not using the "%" symbol, your like clause is working as an "=" since it's trying to match the whole word.
Replace all the "where" clause like this:
->orWhere('forms.name', 'like', "%".$terms_like."%")
This will try to match the word anywhere in the text.
You can try 'like' operator following this:
$users = DB::table('users')
->where('forms.name','LIKE', '%'.$terms_like.'%')
->get();

Categories