Laravel Fluent add select()s in separate places? - mysql

//Earlier in the code, in each Model:
query = ModelName::select('table_name.*')
//Later in the code in a function in a Trait class that is always called
if ($column == 'group_by')
{
$thing_query->groupBy($value);
$thing_query->select(DB::raw('COUNT('.$value.') as count'));
}
Is there a way to append or include a separate select function in the eloquent query builder?
The actual ->select() is set earlier and then this function is called. I'd like to add the count column conditionally in this later function that has the query passed into it.

For future reference, you can use the addSelect() function.
It would be good to have in the documentation, but you'll find it here in the API: http://laravel.com/api/4.2/Illuminate/Database/Query/Builder.html#method_addSelect

Yeah you just insert the block you wanna execute as a function....according to the documentation on Parameter Grouping , you can do like so...by passing the Where a function...
This code below probably wont do what you want, but, its something for you to build off of, and play around with.
DB::table('users')
->where('name', '=', 'John')
->orWhere(function($query)
{
$query->group_by($value);
->select(DB::raw('COUNT('.$value.') as count'));
})
->get();

Try this:
$thing_query->groupBy($value)->get(DB::raw('COUNT('.$value.') as count'));
Also,if you are just trying to get the count and not select multiple things you can use ->count() instead of ->get()

Related

Need suggestion in query builder of Laravel 9 application

How to avoid foreach-loop because Laravel query builder is used to get a single record detail.
When I tried without foreach-loop, the following error occurred "Property [name] does not exist on this collection instance".
Controller
public function show(Student $student)
{
$result = DB::table('students')
->select('*')
->where('id', "=" ,$student['id'])
->get();
foreach($result as $studentData){}
return view('student.show', ['studentData' => $studentData]);
}
Blade View
{{ $studentData->name}}
->get() always returns a Collection, even if there's only one match. If you only want the first record, you can use ->first() instead.
Do you really have to use raw queries? I assume Student is a Laravel Model, in that case, you should be able to use Student::find($id) to get the model directly.

Query builder laravel with and select

I want to show "cars.name" in result.
I need to use "cars.name" value to order later
$this->model
->select("pieces.*", "cars.name")
->where('cars_id', $carId)
->with('cars')
->has('cars', '>=', 1);
How can I do that?
You can try to do it this way by passing a closure function in with():
$this->model
->select("pieces.*")
->where('cars_id', $carId)
->with('cars'=> function ($query) {
$query->select('id','name');
}])
->has('cars', '>=', 1);
It will only select id and username from other table.
Remember that the primary key (id in this case) needs to be the first param in the $query->select() to actually retrieve the necessary results.
the first you have built is just a query, then it needs to be retrieved on the server, use get() and you will see error message. Need more info about the relation between pieces and cars to help. Try it -
$this->model::whereHas('cars',function(builder $query)use($cardId){
$query->where('cars_id', $carId);})->has('cars', '>=', 1)->with('cars')->get();
then obtain cars name via denamic property of a relation

Laravel - Eloquent - Filter based on latest HasMany relation

I have this two models, Leads and Status.
class Lead extends Model
{
public function statuses() {
return $this->hasMany('App\LeadStatus', 'lead_id', 'id')
->orderBy('created_at', 'DESC');
}
public function activeStatus() {
return $this->hasOne('App\LeadStatus', 'lead_id', 'id')
->latest();
}
}
class LeadStatus extends Model
{
protected $fillable = ['status', 'lead_id'];
}
This works fine, now I'm trying to get all Leads based on the 'status' of the last LeadStatus.
I've tried a few combinations with no success.
if ($search['status']) {
$builder = $builder
->whereHas('statuses', function($q) use ($search){
$q = $q->latest()->limit(1);
$q->where('status', $search['status']);
});
}
if ($search['status']) {
$builder = $builder
->whereHas('status', function($q) use ($search){
$q = $q->latest()->Where('status', $search['status']);
});
}
Has anybody done this with Eloquent? Do I need to write some raw SQL queries?
EDIT 1: I'll try to explain again :D
In my database, the status of a lead is not a 1 to 1 relation. That is because I want to have a historic list of all the statuses which a Lead has had.
That means that when a Lead is created, the first LeadStatus is created with the status of 'new' and the current date.
If a salesman comes in, he can change the status of the lead, but this DOES NOT update the previous LeadStatus, instead it creates a new related LeadStatus with the current date and status of 'open'.
This way I can see that a Lead was created on 05/05/2018 and that it changed to the status 'open' on 07/05/2018.
Now I'm trying to write a query using eloquent, which only takes in count the LATEST status related to a Lead.
In the previous example, if I filter by Lead with status 'new', this Lead should not appear as it has a status of 'open' by now.
Hope this helps
Try this:
Lead::select('leads.*')
->join('lead_statuses', 'leads.id', 'lead_statuses.lead_id')
->where('lead_statuses.status', $search['status'])
->where('created_at', function($query) {
$query->selectRaw('max(created_at)')
->from('lead_statuses')
->whereColumn('lead_id', 'leads.id');
})->get();
A solution using the primary key (by Borjante):
$builder->where('lead_statuses.id', function($query) {
$query->select('id')
->from('lead_statuses')
->whereColumn('lead_id', 'leads.id')
->orderBy('created_at', 'desc')
->limit(1);
});
I had this same problem and posted my solution here but I think it's worth re-posting as it improves on the re-usability. It's the same idea as the accepted answer but avoids using joins, which can cause issues if you want to eager load relations or use it in a scope.
The first step involves adding a macro to the query Builder in the AppServiceProvider.
use Illuminate\Database\Query\Builder;
Builder::macro('whereLatestRelation', function ($table, $parentRelatedColumn)
{
return $this->where($table . '.id', function ($sub) use ($table, $parentRelatedColumn) {
$sub->select('id')
->from($table . ' AS other')
->whereColumn('other.' . $parentRelatedColumn, $table . '.' . $parentRelatedColumn)
->latest()
->take(1);
});
});
This basically makes the sub-query part of the accepted answer more generic, allowing you to specify the join table and the column they join on. It also uses the latest() function to avoid referencing the created_at column directly. It assumes the other column is an 'id' column, so it can be improved further. To use this you'd then be able to do:
$status = $search['status'];
Lead::whereHas('statuses', function ($q) use ($status) {
$q->where('status', $userId)
->whereLatestRelation((new LeadStatus)->getTable(), 'lead_id');
});
It's the same logic as the accepted answer, but a bit easier to re-use. It will, however, be a little slower, but that should be worth the re-usability.
If I understand it correctly you need / want to get all Leads with a specific status.
So you probably should do something like this:
// In your Modal
public function getLeadById($statusId)
{
return Lead::where('status', $statusId)->get();
// you could of course extend this and do something like this:
// return Lead::where('status', $statusId)->limit()....->get();
}
Basically I am doing a where and returning every lead with a specific id.
You can then use this function in your controller like this:
Lead::getLeadById(1)

Laravel 5 Eloquent ORM select where - array as parameter

I'm getting grade_id from the database:
$grade_id = DB::table('grades')->where('teacher_id',$teacher_id)->select('grade_id')->get();
and then I want to use that grade_id array in the where eloquent clause so I run
$home_feed = Home::join('home_grade', 'home_grade.home_id', '=', 'homes.id')
->whereIn('grade_id', $grade_id)
->get();
but when I run this I'm getting an error: Object of class stdClass could not be converted to string
What could be the problem? Thanks guys.
Depending on laravels version your $grade_id is either an array or a collection of objects. What you need is an array or a collection of values.
You can achieve that using the pluck() method insted of select() like IzzEps suggested.
But you can get the same result by passing a subquery to the whereIn() method:
$gradeSubquery = DB::table('grades')->where('teacher_id',$teacher_id)->select('grade_id');
$home_feed = Home::join('home_grade', 'home_grade.home_id', '=', 'homes.id')
->whereIn('grade_id', $gradeSubquery)
->get();
This way you will run only one query instead of two.
Update: Before version 5.2 you have to use lists() instead of pluck(). And the whereIn() method doesn't accept a Builder as second parameter. To get the same query you would need to use a closure:
$home_feed = Home::join('home_grade', 'home_grade.home_id', '=', 'homes.id')
->whereIn('grade_id', function($query) use($teacher_id) {
$query->from('grades')
->where('teacher_id', $teacher_id)
->select('grade_id');
})
->get();
your first query is returning a collection, not the grade_id.
Try this instead: $grade_id = DB::table('grades')->where('teacher_id',$teacher_id)->pluck('grade_id');
Using lists worked.
$grade_id = Grade::where('teacher_id', $teacher_id)->lists('grade_id');
They return an array instead of a collection
You need to create the array correctly. To do this use two functions that Eloquent work with: pluck() and toArray(). Look at example below:
$grade_id = DB::table('grades')->where('teacher_id',$teacher_id)->pluck('grade_id')->toArray();

Laravel multiple column eloquent search query

i am very new in Laravel,currently working with Laravel4.I am trying to add a multiple column search functionality in my project.I can do single column eloquent search query,But honestly i have no idea how to do multiple column eloquent search query in laravel.I have two drop down menu
1.Locatiom
2.blood group.
i want to search an user having certain blood group against certain location.That is, user will select a location and blood group from those two drop down menu at a time and hit the search button.
In my database,i have two column, one contains the location and another contains the blood group of a certain user. Now,what should be the eloquent query for such a search?
Simply chain where for each field you need to search through:
// AND
$results = SomeModel::where('location', $location)->where('blood_group', $bloodGroup)->get();
// OR
$results = SomeModel::where('location', $location)->orWhere('blood_group', $bloodGroup)->get();
You can make it easier to work with thanks to the scopes:
// SomeModel class
public function scopeSearchLocation($query, $location)
{
if ($location) $query->where('location', $location);
}
public function scopeSearchBloodGroup($query, $bloodGroup)
{
if ($bloodGroup) $query->where('blood_group', $bloodGroup);
}
// then
SomeModel::searchBloodGroup($bloodGroup)->searchLocation($location)->get();
Just a sensible example, adjust it to your needs.
This is a great way but I think there is an error somewhere as laravel would not allow you to access a non-static function so instead of using
SomeModel::searchBloodGroup($bloodGroup)->searchLocation($location)->get();
you could simply use
SomeModel::BloodGroup($bloodGroup)->Location($location)->get();
take note of the searchBloodGroup has been changed to BloodGroup, that's how you will use it for all others also.
$errors = $connection->table('test_sessions_table')
->where('user_id', $user->id)
->where('status_question', 'false')->count('status_question');
in this method your code takes the following form
SQL code
select count(`status_question`) as aggregate from `test_sessions_table` where `user_id` = ? and `status_question` = ?
orWhere your code will look like this
$errors = $connection->table('test_sessions_table')
->where('user_id', $user->id)
->orWhere('status_question', 'false')->count('status_question');
SQL code
select count(`status_question`) as aggregate from `test_sessions_table` where `user_id` = ? or `status_question` = ?
Personally, I recommend using two ‘where’