Laravel find rows by nested relationship column - php

I have 2 tables reserves and chats, chats belongTo reserves and I want to get all chats where chat.reserve.user_id = Auth::id(). How can I do that in laravel.

I don`t know your models name (need more code in question), but try use
$chats = Chat::query()->whereHas('reserves', function ($q) use ($authID){
$q->where('user_id', $authID);
})->get();
where 'reserves' your relationship and have field user_id. Maybe needed full path to field like 'reserves'.'user_id'
Also look at documentation

Related

Laravel ORM: How to filter records from a table in a M:M relation using a condition of the other table?

I have those two tables: apps and categories, they are in a M:M relationship, I have the apps_categories table in place and the BelongsToMany() relations in their models, they work fine.
Now, in a form I'm displaying all the records in apps, but I want to filter based on category_id, so I have a $categories array where I store the filters.
My problem is solved using the DB facade doing like:
$apps = DB::table('apps')
->join('apps_categories', 'apps.id', '=', 'app_id')
->whereIn('category_id', $categories)
->select('apps.*')
->get();
So, I was wondering if there's a better way, using only the ORM. Thing is I have another table with a M:M relationship to apps, and I'm supposing using the ORM would be a better way to handle both relationships
You could use the whereHas method for this:
$apps = App::whereHas('categories', function ($query) use($categories) {
$query->whereIn('categories.id', $categories);
})->get();
Same as the above but uses an arrow function:
$apps = App::whereHas('categories', fn ($query) => $query->whereIn('categories.id', $categories))->get()
The 1st argument for whereHas is the method name you have used for the relationship in your model (categories) and
1st argument for the whereIn is the table name and field (categories.id).

internal orderBy gets overwritten by external orderBy in Laravel Eloquent

I have a reliationship User hasOne Position and I'm fetching the users, but I want to sort them first by Position->name and then by User->name. I tried the following
<?php
$sorted = Position::where('groupId', $this->groupId)
->whereIn('id', $positions)
->with(['user' => function($query) {
$query->orderBy('user.name'); // internal sort
}])
->orderBy('position.name') // external sort
->get();
This way the results are sorted by the external sort only, or, by Position->name. Different users with the same Position->name are listed unsorted. If I remove the external sort, and leave only the sortBy User->name, it works, BUT only for the names, while positions are random.
I have tried different ways
setting the order in the Position->user relationship, does not work
setting the order in the User->position relationship, does not work
defining only an external orderBy('position.name, user.name'), crashes, saying user table is not in the query.
I also tried following similar questions like
Laravel orderBy on a relationship
Ordering Related Models with Laravel/Eloquent
but they don't seem to be trying to sort the results both by the parent and the relationship. It seems my only solution is to walk the result and sort them in PHP instead of from the DB, but this sounds dumb.
Please advice, thank you.
When you want to sort the parent Position by the relationship User, you need to use a join():
$sorted = Position::where(...)
->whereIn(...)
->with('user')
->join('users', 'users.id', '=', 'positions.user_id') // Or whatever the join logic is
->orderBy('users.name')
->orderBy('positions.name')
->get();
Note: The orderBy() on the user relationship within with() doesn't seem necessary, as by convention, a singular-named relationship should only return 1 record, and sorting on a single record is pointless.
This will return a Collection of Position models, with an attached User model, sorted by the User's name, then the Position's name. You might need to add a select('positions.*') to avoid any ambiguity issues, but this should give you the general idea.

Adding where() on with() eager loading.

I have a little but intricate problem here, I'll try to explain it as best I can.
First I have 3 models, Course, Student, and Quiz,
Student and Course are in a Many to Many relationship
Student and Quiz are in a Many to Many relationship
Quiz and Course are in a One to Many relationship respectively
And I have this following query:
$course = Course::whereSlug($slug)->first(); // Some Course
$quizzes = $course->students()->with('quizzes'); // <-- Here lies the problem.
In the last sentence I want to edit this query to be something like this:
$quizzes = $course->students()->with('quizzes)->where('course_id', $course->id);
I want to do it like that because I want to only grab the quizzes that are related to both the Student model and the Course model.
To give you the full picture, after that I loop through the $students variable in a vue component like this:
<div v-for="student in students"></div>
I am looping with the Student model Because I'm also retrieving different properties other than the quizzes.
But of course when I do it like the query up there I end up retrieving all quizzess for the all students that has a course_id = $course_id.
Required
I want to filter the results to get the quizzes of a student ONLY if they have a course_id of whatever the current courses's id is.
You can use whereHas function to do your job, something like this:
$quizzes = $course
->students()
->whereHas('quizzes', function($q){
$q->where('course_id', $course->id);
})
->with('quizzes)
->get();
I think if you follow the convention you should take Quiz model with students and course cross checked, its upto you. You can find out more on Laravel Documentation Hope this resolves your problem.
Of course after I posted the question I found the answer online randomly, here it is:
$quizzes = $course->students()->with(['quizzes'=> function($query) use ($course) {
$query->where('course_id', $course->id);
}])->get();

Return all data from hierarchical belongsToMany relationship Laravel 5.3

I have models that are Netflix-esque (in the sense of hierarchy). As an example, I have a Lesson which belongsToMany Course which belongToMany Collection, which belongsToMany Subgroup, which belongsToMany Group. Lesson is the lowest level, up to Group as the top level. Going down the chain, each one belongsToMany of the next link down as well.
I am using a filter button that will make a call from Wordpress to my Laravel API. When I pass the group id and the subgroup id, I need to be able to return the collections belonging to the subgroup. But what I need is something like:
$group->with('subgroups')->where('subgroup_id')->with('collections')->with('courses')->with('lessons');
However, that kind of syntax doesn't work. Is there a way to query each level down and get that level's relationships?
If more code is needed, I'd be happy to share more.
The following is untested, but should hopefully either work immediately, or give you an idea as to how to solve the problem yourself.
A couple points:
You can chain relationships within a with call. E.g. courses.lessons will get all courses and related lessons for the collections found.
whereHas allows you to query relationships. In this example, I am looking for all collections, with a subgroup that matches the subgroup ID passed, and that also have a group that matches the group ID passed.
Example:
$groupId = 123;
$subgroupId = 456;
$collections = Collection::with('courses.lessons')
->whereHas('subgroup', function ($query) ($groupId, $subgroupId) {
return $query->whereHas('group', function ($query) use ($groupId) {
return $query->where('id', $groupId);
})
->where('id', $subgroupId);
})
->get();

querying many-to-many-relationship laravel

I have a many-to-many relationship with models Competition and Season with a pivot table named competition_season.
Season->belongsToMany->Competitions->hasMany->Teams->hasMany->Players
I want to query the data of all players in a team in a specific season.
something like
\App\Player::with('team.competition.season')->where('team.competition.season.id', 2);
However since season is a collection (competition has many seasons) at this moment i can never query it like this.
Can someone point me in the right direction to properly select all players in a team in a particular season?
First, you need to add relation hasManyTrough at your model (read more about at: has-many-through)
Then, all you need is "whereHas"
$players = \App\Player::with('season')->whereHas('season', function($q){
$q->where('season.id', '=', 2);
})->get();

Categories