Accessing parent properties inside relationship query - laravel

An example:
$passing_students = App\Exam::whereHas('students', function ($query) {
$query->where('mark', '>=', $exam->pass_mark);
})->get();
I am interested in fetching all exams with students who passed however in the relationship query function I'm not sure how to access the parent model's properties such that I can complete the comparison. What should be in place of $exam->pass_mark?
Note that I'm looking for a solution that is done within the single query builder as I'm aware that this can be easily done in a separate foreach loop.

Probably instead of:
$query->where('mark', '>=', $exam->pass_mark);
you should use here:
$query->whereColumn('mark', '>=', 'exams.pass_mark');
Above exams.pass_mark is name of Exam model table (I assumed you use exams and column name from this table.

Related

Laravel query use parent column inside whereRelation

I have problem with my eloquent query, i need to use data of my base model into whereRelation.
I tried this query bottom, but results was not what i except. The query return me all users who have one city relation, not only user who have city updated between my last user sync.
$users = People::whereRaw('TIMESTAMPDIFF(SECOND, people.latest_sync, people.updated_at) > 20')
->orWhereRelation('city', 'updated_at', '>', 'people.updated_at')
->get();
I'v tried people.updated_at and latest_sync in value of my Where Relation
Do i need to make pure SQL Raw query with classic join ?
PS: the first whereRaw is ok, and work (i really need)

How return all rows for groupBy

I use the query to get the models that the user has, but only 1 model is returned for each user. How to get all? If I set $count=3 I should receive 3 or more models in group, but only first row is returned
$items->where(/*.....*/)
->groupBy('user_id')
->havingRaw("COUNT(*) >= {$count}")->get()
UPDATE
I solved it. I created a separate function for preparing the query and used it 2 times.
I think this may be an incorrect solution, but it works
$items = Items::query();
$this->prepareQuery($request, $items)
$items->whereHas('user', function ($q) use ($count, $request){
$q->whereHas('items', function ($query) use ($request){
$this->prepareQuery($request, $query);
}, '>=', $count);
})
->paginate(4);
This may work.Sometimes take can help.
$items->where(/*.....*/)
->groupBy('user_id')
->take({{$count}});
If you have relationships set up you can quite simply call:
$model->models()
$model being the model you're wanting the list for.
models() being the name of the relationship between the two items.
For example, a post may have many comments. You can call $post->comments() to get a list of the posts comments.
You may also query this from the database directly with some eloquent magic.
Post::with('comments')->where(/*....*/)->get();
EDIT:
You can check to see if a model has X number of related models like so.
Post::has('comments', '>=', 3)->where(/*...*/)->get();

Laravel how to query a pivot table created_at timestamp equal to a date

I have users and habits, and a habit_user table to join them.
I am querying like this:
$track = $h->userAnswers()->where('user_id', Auth::user()->id)->wherePivot('created_at', '=', Carbon\Carbon::now()->subDays($i))->first();
This is running in a loop that is counting back for 7 days. there is a record in the db that is created_at: 2018-10-23 04:48:44
In my habit model I have the method you'd expect:
public function userAnswers()
{
return $this->belongsToMany('App\Habit', 'habit_user_answers')->withTimestamps()->withPivot('answer_one', 'created_at')->orderBy('pivot_created_at', 'desc');
}
Why won't query get a record?
You are comparing the date time so only if both date and time is same, the query will throw a result.
You can compare dates like so:
wherePivot('created_at', '>=', Carbon\Carbon::now()->subDays($i)->startOfDay())->wherePivot('created_at', '<=', Carbon\Carbon::now()->subDays($i)->endOfDay())
First, I think you need to consider Laravel conventions about naming methods and properties.
I'll assume the following based on your structure that includes users and habits. So, we have a User model and a Habit model, a user belongsToMany habits and a habit belongsToMany users. Also the pivot table habit_user contains extra fields like answer_one, answer_created_at and timestamps.
If you want now to query the habits now you have two solutions:
1- using wherePivot()
auth()->user()->habits()->wherePivot('answer_created_at', today())->get();
auth()->user()->habits()->wherePivot('answer_one', '!=', 'something')->get();
2- using whereHas()
auth()->user()->whereHas('habits', function($query){
$query->where('pivot.answer_one', 'something');
})->get();

Laravel Eloquent - How Do You Add a Where Condition to a Distantly Related Model Using the ORM?

I currently have the following:
Cars::with('cases')->with(['parts', 'parts.engines', 'parts.engines.metals'])
->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');
The above will list all rows in my cars table along with the metal associated with the engine in each of those cars. The metals table is related to the cars table through the parts and then the engines tables.
I've tried using:
Cars::with('cases')->whereHas(['parts', 'parts.engines', 'parts.engines.metals'], function($query){
$query->where('weight', '=', 45)
})->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');
But this errors out since whereHas() does not accept an array for its first parameter and I don't see a way to link to distant relationships with it.
How do I apply a WHERE conditional on a column in the metals table using the built-in ORM?
whereHas() only needs the name of the relationship for which you'd like to add the conditions. So, if you're trying to add the condition to the metals, you just need to restrict the parts.engines.metals relationship.
On a side note, when you eager load nested relationships, you don't need to also specify to load the intermediate relationship. That is, when you eager load parts.engines, you don't need to also eager load parts.
So, your query would look something like:
Cars::with(['cases', 'parts.engines.metals'])
->whereHas('parts.engines.metals', function($query) {
$query->where('weight', '=', 45)
})
->orderBy('car_name', 'DESC')
->orderBy('id', 'DESC');
This query will only retrieve cars that have a related metal with a weight of 45. Additionally, for those cars that are retrieved, it will also eager load all of the cases, parts, engines, and metals related to those cars.
I think you mean this:
Cars::with(['cases', 'parts', 'parts.engines', 'parts.engines.metals' => function($query){
$query->where('weight', '=', 45);
}])->orderBy('car_name', 'DESC')->orderBy('id', 'DESC');

Laravel: Difference between where and whereHas

What is the difference between the two methods where() and whereHas()? They both seem to be quite similar in the laravel documentation.
The method where() behaves like a regular SQL WHERE query part.
The method has() uses foreign key relationships to return something which has something else. For instance, Student::has('classes')->get(); would return all students who have classes.
The method whereHas() is like a regular has(), but it lets you put constraints on the search. Unlike where(), this is done on the child table rather than the parent one. Here's an example:
$students = Student::where('name', 'Pingu') // constrains the students table
->whereHas('classes', function($query) {
$query->where('name', 'like', '%physics%'); // constrains the classes table
})->get();
In this highly realistic example, you'd want all students with a name of Pingu, who are taking some class in physics.

Resources