Search and sort in laravel? - php

In laravel, I know you can do
$users = Post::where('hide', '=', 0)->take(40)->get();
to get all Post-objects where hide = 0 and
$users = Post::orderBy('created_at', 'DESC')->take(20)->get();
to sort them, but what if I want to do both?

You should be able to do
$users = Post::where('hide', '=', 0)->orderBy('created_at', 'desc')->take(20)->get();
You can continue to chain methods from the query builder after the where.

Related

Is there any way to get two different results with single query based on condition?

I am trying to get two different results from single query but the problem is both conditions get applied on last query.
for example
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
->where('role_user.role_id',2)
->whereNotNull('users.email_verified_at');
$newMailUsers = $getUser->where('new_mail',0)->get();
$topSellingMailUsers = $getUser->where('topselling_mail',0)->get();
but when i checked sql query of $topSellingMailUsers i saw that both the conditions of new_mail and topselling_mail applied in $topSellingMailUsers query what i want is it should not consider mail condition in query.
how can i get two different results of $newMailUsers, $topSellingMailUsers based on both conditions separately.
Every time you use where() method you are mutating $getUser query builder.
You can chain your query builder with clone() method and this will return another query builder with the same properties.
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
->where('role_user.role_id',2)
->whereNotNull('users.email_verified_at');
$newMailUsers = $getUser->clone()->where('new_mail',0)->get();
$topSellingMailUsers = $getUser->clone()->where('topselling_mail',0)->get();
you need to clone Builder object to reuse it
$selectFields = [
'users.id',
'users.name',
'users.email',
'users.identity_status',
'users.email_verified_at',
'role_user.role_id'
];
/** #var Illuminate\Database\Eloquent\Builder */
$getUser = User::join('role_user', 'role_user.user_id', 'users.id')
->select($selectFields)
->where('role_user.role_id', 2)
->whereNotNull('users.email_verified_at');
$newMailUsers = (clone $getUser)->where('new_mail', 0)->get();
$topSellingMailUsers = (clone $getUser)->where('topselling_mail', 0)->get();
Well, if you have relations set up on models will be easier, but still can do it:
// Let's say you pass sometimes the role_id
$role_id = $request->role_id ?? null;
$getUser = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id')
// ->where('role_user.role_id',2) // replaced with ->when() method
->when($role_id, function ($query) use ($role_id){
$query->where('role_user.role_id', $role_id);
})
->whereNotNull('users.email_verified_at');
This way it will return users with ALL ROLES or if ->when(condition is TRUE) it will return users with the role id = $role_id.
You can use multiple ->when(condition, function(){});
Have fun!
Instead of firing multiple queries you can do it in a single query as well by using collection method as like below.
$users = User::join('role_user','role_user.user_id','users.id')
->select('users.id','users.name','users.email','users.identity_status','users.email_verified_at','role_user.role_id', 'new_mail', 'topselling_mail')
->where('role_user.role_id',2)
->where(function($query) {
$query->where('new_mail', 0)->orWhere('topselling_mail', 0);
})
->whereNotNull('users.email_verified_at')
->get();
$newMailUsers = $users->where('new_mail',0)->get();
$topSellingMailUsers = $user->where('topselling_mail',0)->get();

Order and Sub Order collection - laravel 7 (Simple)

lets say I have a collection of users Users::all()
I would like to take sort/order it like such Users::all()->sort('created_at', 'DESC')
then I would like to sub order it by an array like [1,5,3,9,4,8] so perhpas a call like this Users::all()->sort('created_at', 'DESC')->sortBy("id", [1,5,3,9,4,8])
Any Advice?
Edit 1
I have found this, is this correct to use?
$ids = collect([1,5,3,9,4,8]);
$users = Users::all()->sort('created_at', 'DESC');
$users = $ids->map(function($id) use($users) {
return $users->where('cat_id', $id)->first();
});
I think you could just invoke orderBy() twice.
$ids = [1,5,3,9,4,8];
$users = Users::all()
->orderBy('created_at', 'desc')
->orderBy($ids)
->get();
Does this answer your question?
You can use whereIn like this probably:
$ids = [1,5,3,9,4,8];
$users = Users::all()
->orderBy('created_at', 'desc')
->whereIn('cat_id', $ids)
->get();
https://laravel.com/docs/9.x/queries#additional-where-clauses
The whereIn method verifies that a given column's value is contained within the given array
So I found a solution.
$ids = json_decode($interview->question_ids ?? '[]');
if(count($ids) == 0){ // if empty create new id array and save to DB
$ids = collect(questions::all()->where('interview_id', $interview->id)->pluck('id')->toArray());
$interview->question_ids = json_encode($ids);
$interview->save();
}
$questions = questions::all()->where('interview_id', $interview->id)->sortBy([
['order_timestamp', 'asc'],
['created_at', 'asc'],
]);
$questions = $ids->map(function($id) use($questions) {
return $questions->where('id', $id)->first();
});
$questions = $questions->flatten();

Laravel 5.4 Eloquent get x random records from collection where property is null

Learning eloquent/laravel. I have a collection:
$regions = Region::with('neighbors')
->join('cards', 'cards.id', '=', 'regions.risk_card_id')
->get();
I have a value or rows:
$regionsPerUser = 8;
I am doing this to pull random records:
$regions = $regions->random($regionsPerUser);
But I need to filter this selection where $regions->user_id is not null.
Is there a way to filter the random call as part of chaining?
I tried this which does not work:
$regions = $regions->whereNotNull('user_id')->random($regionsPerUser);
And I am wondering if there is a way to neatly do this in one chained statement as opposed to going down the path of filter / map.
Why not just add your conditions to a sql-query:
$regions = Region::with('neighbors')
->join('cards', 'cards.id', '=', 'regions.risk_card_id')
->whereNotNull('user_id')
->inRandomOrder()
->limit($regionsPerUser)
->get();
If you already have a collection then you can do something like:
$regions = $regions
->filter(function ($value) {
return !is_null($value['user_id']);
})
->random($regionsPerUser);

eloquent laravel: How to get a row count from a ->get()

I'm having a lot of trouble figuring out how to use this collection to count rows.
$wordlist = \DB::table('wordlist')->where('id', '<=', $correctedComparisons)
->get();
I have tried adding->count() but didn't work. I have tried doing count($wordlist). I'm not really sure what to do without needing a second request as a->count() method.
Answer has been updated
count is a Collection method. The query builder returns an array. So in order to get the count, you would just count it like you normally would with an array:
$wordCount = count($wordlist);
If you have a wordlist model, then you can use Eloquent to get a Collection and then use the Collection's count method. Example:
$wordlist = Wordlist::where('id', '<=', $correctedComparisons)->get();
$wordCount = $wordlist->count();
There is/was a discussion on having the query builder return a collection here: https://github.com/laravel/framework/issues/10478
However as of now, the query builder always returns an array.
Edit: As linked above, the query builder now returns a collection (not an array). As a result, what JP Foster was trying to do initially will work:
$wordlist = \DB::table('wordlist')->where('id', '<=', $correctedComparisons)
->get();
$wordCount = $wordlist->count();
However, as indicated by Leon in the comments, if all you want is the count, then querying for it directly is much faster than fetching an entire collection and then getting the count. In other words, you can do this:
// Query builder
$wordCount = \DB::table('wordlist')->where('id', '<=', $correctedComparisons)
->count();
// Eloquent
$wordCount = Wordlist::where('id', '<=', $correctedComparisons)->count();
Direct get a count of row
Using Eloquent
//Useing Eloquent
$count = Model::count();
//example
$count1 = Wordlist::count();
Using query builder
//Using query builder
$count = \DB::table('table_name')->count();
//example
$count2 = \DB::table('wordlist')->where('id', '<=', $correctedComparisons)->count();
Its better to access the count with the laravels count method
$count = Model::where('status','=','1')->count();
or
$count = Model::count();
also, you can fetch all data and count in the blade file.
for example:
your code in the controller
$posts = Post::all();
return view('post', compact('posts'));
your code in the blade file.
{{ $posts->count() }}
finally, you can see the total of your posts.
//controller $count = Post::count(); return view('post', compact('count'));
//blade {{$count}}
or
//controller $posts = Post::all(); return view('post', compact('posts'));
//blade{{count($posts)}}

How to split up an Eloquent model query

I'm trying to break up an Eloquent query like this
$query = new Product;
if (!empty($req->query['id'])) {
$query->where('id', '=', '1');
}
$products = $query->get();
The result above gives me all products in the database. This however, does in fact work.
$products = Product::where('id', '=', '1')->get();
Is there a way to do this?
In Laravel 4 you need to append your query parameters to your query variable. In Laravel 3, it would work like you're doing.
This is what you need to do (I'm unsure if it will work with new Product tho):
$query = new Product;
if (!empty($req->query['id'])) {
$query = $query->where('id', '=', '1');
}
$products = $query->get();
Your code does not make sense. If you make a new Product - then it will never have an ID associated with it - so your if (!empty($req->query['id'])) will always be false.
Are you just trying to get a specific product idea?
$products = Product::find(1);
is the same as
$products = Product::where('id', '=', '1')->get();

Categories