Trouble converting an SQL query to Eloquent - laravel-5

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();

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

How do I search by a table included using with() statement

I am trying to search with a column on a connected table using with. According to laravel the following should work.
$lineItems = Invoice::with(['invoiceHeader' => function ($query) {
$query->where('community_id', '=', 1);
}, 'invoiceLineItems'])
->limit(10)
->get()
->toArray();
However, I don't get anything from the invoiceHeader table and I get all the invoices available. If I take out the function I get the same but with invoiceHeader's table values showing up.
$lineItems = Invoice::with(['invoiceHeader', 'invoiceLineItems'])
->limit(10)
->get()
->toArray();
It seems I might be doing something of a right join where I get all the Invoices but then only the invoiceHeader values when applicable to the foreign key.
Edit:
I put ->toSql(); after the limit() and it shows I only get the following.
"select * from `invoice` limit 10"
You should use whereHas mixing with with:
$lineItems = Invoice::with(['invoiceHeader', 'invoiceLineItems'])
->whereHas('invoiceHeader', function ($query) {
return $query->where('community_id', 1);
})
->limit(10)
->get()
->toArray();

Laravel: Use order by in combination with whereHas

I want to retrieve a collection of data, which is ordered by the start_date of the relation
Basically I want to achieve this, with Laravel Models (the code below works perfectly)
$posts = DB::table('posts')
->leftJoin(
'threads',
'posts.id',
'=',
'threads.postable_id'
)
->where('threads.postable_type', '=', 'App\Post')
->orderBy('threads.start_date')
->paginate($request->input('limit', 2));
So in this case, I'm fetching ALL Posts and those are ordered by the start_date of the thread relation.
Those are not my actual tables but this works perfectly!
Because I'm using https://laravel.com/docs/8.x/eloquent-resources this is not the ideal solution to retrieve sorted data.
So instead I want to use the orderBy clause somewhere here
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now());
});
But I just cannot make this work. I've tried this
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
and I also appended this to the actual relation:
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
If you look at your code:
$posts = Post::whereHas('thread', function ($query) {
$query->where('end_date', '>=', Carbon::now())
->orderBy('start_date');
});
the whereHas will only return Post associate with a thread which the function return true.
Try this:
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
This will fetch all Post with Thread only if they have at least one Thread and then orderBy the start_date of the Thread.
You don't have to do the whereHas function because when you call ->with('thread') it'll use you this :
public function thread(): MorphOne
{
return $this->morphOne('App\Thread', 'postable')->orderBy('start_date');
}
whereHas doesnt retrieve the relationship.
If you need even more power, you may use the whereHas and orWhereHas methods to define additional query constraints on your has queries, such as inspecting the content of a comment: Laravel whereHas
Don't do :
$posts = Post::with('thread')->orderBy('thread.start_date');
If there is no thread on some post, post without thread will be fetch with value null for their key thread and you will have an unexpected result when you try to orderBy.
First of all I want to thank Elie Morin for his help but I found out that I definitely need to use joins for that task.
In my example, I wanted to order the main query (posts) by the relation's start_date
Doing what you suggested
$posts = Post::with('thread')->has('thread')->orderBy('thread.start_date')->get();
Would only order the thread by start_date and not the ENTIRE query.
Which is why I came up with something like this:
$posts = Post::has('thread')
->select('posts.id')
->leftJoin(
'thread',
'posts.id',
'=',
'thread.postable_id'
)
->where('thread.postable_type', '=', 'App\Post')
->where('thread.end_date', '>=', Carbon::now())
->orderBy('thread.start_date')
->with('thread');
return PostResource::collection($posts->paginate(2));

Laravel nested whereIn from multiple tables

I'm using Laravel 5.7. How do i rewrite below code as a single nested query?
I'm currently fetching the result using 2 database queries. I go through some of the answers in stackoverflow, but i still have doubts in nesting multiple tables
$connectedParts = DB::table('part_connections as c')
->join('parts_master as p', 'p.id', '=', 'c.part_number_id')
->where('c.part_number_id', $partId)
->where('p.id', $partId)
->pluck('connected_to');
$connectedComponents = DB::table('part_connections as pc')
->join('parts_master as pm', 'pm.id', '=', 'pc.connected_to')
->where('part_number_id',$partId)
->where('pm.part_type','1')
->whereIn('connected_to', $connectedParts)
->pluck('connected_to');
Any help would be greatly appreciated.
Set your relationship properly in your model first then try this query:
//PartConnection model - add for eager loading
public function master() {
return $this->belongsTo('PartMaster::class', 'connected_to', 'id');
}
$query = PartConnection::whereHas(‘master’, function($qry)) use ($partId) {
$qry->where(‘parts_master.id’, $partId);
$qry->where(‘parts_master.part_type’, 1);
});
$query->where(‘part_number_id’, $partId);
$connectedComponents = $query->get();
update
Try this then:
$connectedComponents = DB::table('part_connections as pc')
->join('parts_master as pm', function($join) {
$join->on('pc.connected_to', '=', 'pm.id');
$join->on('pc.part_number_id', '=', 'pm.id');
}) //updated this - removed ;
->where('part_number_id',$partId)
->where('pm.part_type','1')
->get();

Laravel select * where id =(select id )

Using Laravel eloquent how do I make a query like this:
select * from branches where user_id =(select id from users where name ='sara' )
Assuming that you have a user relationship in your Branch model you could use whereHas:
$branches = Branch::whereHas('user', function ($query) {
$query->where('name', 'sara');
})->get();
Update
If you're using v8.57.0 or above, you can now use the whereRelation() method instead:
Branch::whereRelation('user', 'name', 'sara')->get();
$id = Users::select('id')->where('name','sara')->first();
$barnches = branches::where('id',$id)->get();
Here Users and branches are models , first is using for 1 row and get for many rows
I would split it into two queries. First getting the id, then getting the list. Expecting your models to be called "User" and "Branches"
$user = User::where('name', 'sara');
$id = $user->id;
$branches = Branch::where('id', $id);
This site may help you Link
Try this.
$name = 'sara';
$results = BranchModel::whereIn("user_id", function ($query) use ($name) {
$query->select("id")
->from((new UserModel)->getTable())
->where("name", $name);
})->get();
You can use this:
$users = User::whereName("sara")->get()->pluck('id');
Branch::whereIn('user_id',$users)->get();

Resources