How to select instances for specific 'n' on m:n relationships? - laravel

I have two models Teacher and Category. These two have Many to Many relationship.
I want to get those teachers who have one category equal to "OLevels". Which method of eloquent is used for it or is there any other way I can get it?
Is there anyway to get it as:
$teachers = Teacher::where('category', '=', 'OLevels')->get();

You can use whereHas for that:
$category = 'OLevels';
$teachers = Teacher::whereHas('category', function($q) use ($category){
$q->where('name', $category);
})->get();

You could make use of eager loading with constraints
$teachers = Teacher::with(['category' => function($query)
{
$query->where('category', '=', 'OLevels');
}])->get();
Further info in the documentation.

Related

laravel eloquent Filter relations Model values with Base Model id

$subTasks = SubTask::with(['task'])
->with(['users.subTaskInfos' => function ($q) {
$q->orderBy('created_at', 'desc');
$q->where('sub_task_id', '=', ?);
}])
->where('active', 1)
->get();
I want to pass Base Model SubTask id in question mark section to filter out relations data and relation collection of data. Can anyone help?
One way to achieve what you are attempting is to lazy eager load users.subTaskInfos - keeping the number of queries the same
$subtasks = SubTask::with(['task'])->where('active', 1)->get();
$subtasks->load(['users.subTaskInfos' => function($q) use($subtasks) {
$q->whereIn('sub_task_id', $subtasks->pluck('id')
->orderByDesc('created_at');
});

Laravel Query Item from table with selected relationships from another table

There are two tables which are related - Product and SalesForecast. I want to query products of a certain supplier with sales forecast from a period.
Relationships are established. My query is as follows:
$products = Product::where('supplier_id', $supplier)
->whereHas('stock_forecasts_fk', function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin);
$query->whereDate('date', '<', $end);
})
->get();
The relationship in the product model is as follows:
public function stock_forecasts_fk()
{
return $this->hasMany('App\Models\StockForecast');
}
This query does not work 100%. I want all products of that supplier to come (whether they have forecast or not). If they have a forecast, I need forecasts for that period only. Otherwise, that product will have not, forecast. But All product needs to come. Can someone advise how to fix this query so the result is as follows:
All products of suppliers come with relevant forecasts of between begin and end dates. If there is no forecast, then the product can come with no forecast.
You have to query with eager loading the relationship. with whereHas, only matching related value products will be collected. use with closure to query in related table
$products = Product::with(['stock_forecasts_fk' => function($query) {
$query->whereDate('date', '>', $begin)
->whereDate('date', '<', $end);
}])
->where('supplier_id', $supplier)
->get();
You can use with and pass a closure with your conditions to it:
$products = Product::where('supplier_id', $supplier)
->with(['stock_forecasts_fk' => function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin)
->whereDate('date', '<', $end);
}])
->get();
From the docs:
Constraining Eager Loads
Sometimes you may wish to eager load a relationship, but also specify
additional query conditions for the eager loading query. Here's an
example:
$users = App\Models\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
In this example, Eloquent will only eager load posts where the post's
title column contains the word first.
From the document that I've read here.
whereHas only includes Product which has stock_forecasts_fk, and discards Product which doesn't.
To select all product regardless it has stock_forecasts_fk, you should've use with.
$products = Product::where('supplier_id', $supplier)
->with([
'stock_forecasts_fk' => function ($query) use ($begin, $end) {
$query->whereDate('date', '>', $begin);
$query->whereDate('date', '<', $end);
}
])
->get();

Trouble converting an SQL query to Eloquent

Trying to get this query to work in eloquent
A user can be in multiple teams however I want to generate a list of users NOT in a specific team. The following SQL query works if executed directly but would like to make it cleaner by converting it to eloquent
SELECT * FROM users LEFT JOIN team_members ON team_members.member_id = users.id WHERE NOT EXISTS ( SELECT * FROM team_members WHERE team_members.member_id = users.id AND team_members.team_id = $team_id )
This should provide a list of all the users that are not members of team $team_id
This is a guess ad you do not give much info on your Eloqent models but here is a hint of where to go:
User::doesnthave('teamMembers', function($builder) use($team_id){
return $builder->where('team_members.team_id');
});
That is assuming you have a "User" model with a "teamMembers" relationship setup on it
You may have a closer look in the Laravel docs for doesntHave
Laravel 5.8
Let's assume you have model name "User.php"
& there is method name "teamMembers" in it.
Basic
$users = User::doesntHave('teamMembers')->get();
Advance
use Illuminate\Database\Eloquent\Builder;
$users = User::whereDoesntHave('teamMembers', function (Builder $query) {
$query->where('id', '=', {your_value});
})->get();
You can find details description in this link >>
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-absence
Laravel 5.2
Example:
DB::table('users')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Check this link for advance where clause:
https://laravel.com/docs/5.2/queries#advanced-where-clauses
You can use below example
$list = User::leftJoin('users', 'users.id', '=', 'team_members.member_id')
->whereNotExists(function ($query) use ($team_id) {
$query->from('team_members')
->whereRaw('team_members.member_id = users.id')
->where('team_members.team_id', '=', $team_id);
})
->get();

Getting a relationship with a condition?

I have category and article tables, they are in a many to many relationship. i have the relationships set up on the models.
How can I get all articles where a category id is = 1?
I've tried:
Article::whereHas('category', function ($query) use ($id) {
$query->where('category_id', $id);
})->get();
The above works, but seems clunky, is there a more efficient way in eloquent to do this?
You can use eager loading technique.
Article::with(['category', function ($query) use ($id) {
$query->where('category_id', $id);
}])->get();
The following groupBy code is assuming that Category::find($id)->articles is not an option for whatever reason.
What about groupBy?
Article::groupBy('category')
->having('category', $id)
->get();
whereHas will return articles that match that condition, but won’t filter articles then fetched by the same conditions. You could therefore create an anonymous function that contains the constraints, and pass it to both the whereHas and with methods:
$filter = function ($query) use ($categoryId) {
$query->where('category_id', '=', $categoryId);
};
Article::whereHas('category', $filter)
->with(['category' => $filter])
->get();

Order by related table column

I have a query like:
$users = User::with('role')
->get();
How can I order the results by the related table, so it's something like:
$users = User::with('role')
->orderBy('role.id', 'DESC')
->get();
Is there a way to do it without joining the role table (since we're already doing with('role')?
what are you trying to order. the list of users or the roles.
if you are trying to sort the users base on role do.
$users = User::with('role')->orderBy('role_id', 'DESC')
->get();
if you are trying to sort the roles of the user then pocho's answer is correct.
$users = User::with(array('role' => function($query)
{
$query->orderBy('id', 'DESC');
}))->get();
From the documentation:
$users = User::with(array('role' => function($query)
{
$query->orderBy('id', 'DESC');
}))->get();
You can also do a raw query using DB::raw like in the examples here.
You can always sort the returned collection quite easily...
$users = User::with('role')
->get()
->sortBy(function($user, $key)
{
return $user->role->id;
});
This is assuming a user hasOne or belongsTo a role. If your relationship is something that can return multiple roles, then it becomes a bit more complex because you need to decide which of the user's roles to sort by.

Resources