How to query relational data in laravel using eloquent - laravel

I have Project Model each Project has Many Positions from Position Model and each positions has Many Employees in Employee Model
Now I want to query all employees id's of the particular project regardless their position,
How can I achieve this using eloquent?

Roughly you would do something similar to this, where you can use whereHas to create nested queries on relations.
$employeeIdsToFilter = [1,2,3];
$filteredProjects = Project::query()->
whereHas('positions' , function ($query) use ($employeeIdsToFilter) {
$query->whereHas('employees', function($query) use ($employeeIdsToFilter) {
$query->whereIn('id', $employeeIdsToFilter);
});
})->get();

You can use the HasManyThough relation. Here is the Link

Related

How to translate the SQL query to Laravel Eloquent query?

I'm trying to make a complex query using Laravel Eloquent. I know how to do it using raw SQL query, but I don't have any idea how to do it using Eloquent.
Here is my SQL query, and it works perfectly:
select *
from students
where exists(select *
from (select student_movements.id AS sm_id, student_movements.direction, student_movements.deleted_at
from student_movements
inner join student_student_movements
on student_movements.id = student_student_movements.student_movement_id
where students.id = student_student_movements.student_id
and student_movements.deleted_at is null
order by student_movements.id desc
limit 1) as last_sm
where last_sm.direction = 1 AND last_sm.date >= 5-5-2022
);
My models have many-to-many relation using student_student_movements table:
Student
public function studentMovements(): BelongsToMany
{
return $this->belongsToMany(
StudentMovement::class,
'student_student_movements',
);
}
StudentMovement
public function students(): BelongsToMany
{
return $this->belongsToMany(
Student::class,
'student_student_movements'
);
}
My goal is to get all Students, who have the last Movement where direction = 1 and the date of the last Movement >= $someDate.
So, my question is: how to translate the SQL query to Eloquent? I saw many similar questions, but they are not helping me.
Thanks for any advice.
Use the whereHas method, then fine tune the sub query inside the closure to your needs.
You can use the whereHas and orWhereHas methods to define
additional query constraints on your has queries.
There is an example like that in laravel documentation
use Illuminate\Database\Eloquent\Builder;
// Retrieve posts with at least one comment containing words like code%...
$posts = Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'code%');
})->get();
// Retrieve posts with at least ten comments containing words like code%...
$posts = Post::whereHas('comments', function (Builder $query) {
$query->where('content', 'like', 'code%');
}, '>=', 10)->get();
check the documentation here

Laravel eloquet check non existing many to many relation

I'm having trouble to write query in laravel eloquent ORM.
I have a proyect table, where you can assign users, in a many to many relationship
In the view to asign users, I have a selector, but I want to show only the users not already assigned to the proyect and checking also that the user belongs to the company that created the proyect (user.company_id=proyect_id)
In a normal query should me something like this, having $company_id and $proyect_id from the controller.
select * from users u left join proyect_user pu on u.id=pu.user_id and
pu.proyect_id = $proyect_id where u.company_id=$company_i and
proyect_id is null;
The query works, but I would like to use Eloquent. ¿Any idea how to do it?
It depends on how you declared the relationship in the User model. But I would do something like this:
$users = User::whereHas('company', function ($query) use ($companyId) {
$query->where('id', $companyId)
})->whereDoesntHave('proyects', function ($query) use ($proyectId) {
$query->where('id', $proyectId);
})->get();

How to use Laravel Eloquent whereIn function on another table?

If two tables have relationship between them, I am using with function to get records considering value within condition from another table. For example:
Table::where('column1', 'text1')->with('table2.column2', 'text2')
My question is, how can I use whereIn function to set array of allowed values in table2?
Table::where('column1', 'text1')->whereIn('table2.column2', ['text2', 'text3'])
Try this
Table::where('column1', 'text1')
->whereHas('table2',function($q) {
$q->whereIn('column2', ['text2','text3']);
});
You must have to define relationship in model
This is the best practice
Refer: Laravel Eloquent Relationship
Refer: Query On Relationship
I would go with Laravel's Constrained eager load to load your relationship.
Example
Table::where('column1', 'text1')
->with(['table2' => function ($query) {
$query->whereIn('column2', ['text2', 'text3'])
}])
->get();
If you don't need to load the relationship, then going with the whereHas solution provided by #bhavinjr is the best.
From the documentation :
Eager Loading Multiple Relationships
Sometimes you may need to eager load several different relationships in a single operation. To do so, just pass additional arguments to the with method:
$books = App\Book::with(['author', 'publisher'])->get();
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\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();`
You can take a look at Laravel API to have a deeper understanding of the with method.

Where clause inside whereHas being ignored in Eloquent

Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.

Eloquent filter on pivot table created_at

I want to filter the contents of two tables which have an Eloquent belongsToMany() to each other based on the created_at column in the pivot table that joins them. Based on this SO question I came up with the following:
$data = ModelA::with(['ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
}])->get();
Here I'm using a simple test column to check if it's working, this should be 'created_at'.
What happens though is that I get all the instances of ModelA with the ModelB information if it fits the criteria in the wherePivot(). This makes sense because it's exactly what I'm telling it to do.
My question is how do I limit the results returned based on only the single column in the pivot table? Specifically, I want to get all instances of ModelA and ModelB that were linked after a specific date.
OK, here it goes, since the other answer is still wrong.
First off, wherePivot won't work in whereHas closure. It's BelongsToManys method and works only on the relation object (so it works when eager loading).
$data = ModelA::with(['relation' => function ($q) use ($someDate) {
$q->wherePivot('created_at', '>', $someDate);
// or
// $q->where('pivot_table.created_at', '>', $someDate);
// or if the relation defines withPivot('created_at')
// $q->where('pivot_created_at', '>', $someDate);
}])->whereHas('ModelB', function ($q) use ($someDate) {
// wherePivot won't work here, so:
$q->where('pivot_table.created_at', '>', $someDate);
})->get();
You are using Eager Loading Constraints, which constrain only, like you said, the results of the related table.
What you want to use is whereHas:
$data = ModelA::whereHas('ModelB' => function ($q) {
$q->wherePivot('test', '=', 1);
})->get();
Be aware that ModelB here refers to the name of the relationship.

Resources