Where NOT in pivot table - laravel

In Laravel we can setup relationships like so:
class User {
public function items()
{
return $this->belongsToMany('Item');
}
}
Allowing us to to get all items in a pivot table for a user:
Auth::user()->items();
However what if I want to get the opposite of that. And get all items the user DOES NOT have yet. So NOT in the pivot table.
Is there a simple way to do this?

Looking at the source code of the class Illuminate\Database\Eloquent\Builder, we have two methods in Laravel that does this: whereDoesntHave (opposite of whereHas) and doesntHave (opposite of has)
// SELECT * FROM users WHERE ((SELECT count(*) FROM roles WHERE user.role_id = roles.id AND id = 1) < 1) AND ...
User::whereDoesntHave('Role', function ($query) use($id) {
$query->whereId($id);
})
->get();
this works correctly for me!
For simple "Where not exists relationship", use this:
User::doesntHave('Role')->get();
Sorry, do not understand English. I used the google translator.

For simplicity and symmetry you could create a new method in the User model:
// User model
public function availableItems()
{
$ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
return \Item::whereNotIn('id', $ids)->get();
}
To use call:
Auth::user()->availableItems();

It's not that simple but usually the most efficient way is to use a subquery.
$items = Item::whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
})
->get();
If this was something I did often I would add it as a scope method to the Item model.
class Item extends Eloquent {
public function scopeWhereNotRelatedToUser($query, $user_id)
{
$query->whereNotIn('id', function ($query) use ($user_id)
{
$query->select('item_id')
->table('item_user')
->where('user_id', '=', $user_id);
});
}
}
Then use that later like this.
$items = Item::whereNotRelatedToUser($user_id)->get();

How about left join?
Assuming the tables are users, items and item_user find all items not associated with the user 123:
DB::table('items')->leftJoin(
'item_user', function ($join) {
$join->on('items.id', '=', 'item_user.item_id')
->where('item_user.user_id', '=', 123);
})
->whereNull('item_user.item_id')
->get();

this should work for you
$someuser = Auth::user();
$someusers_items = $someuser->related()->lists('item_id');
$all_items = Item::all()->lists('id');
$someuser_doesnt_have_items = array_diff($all_items, $someusers_items);

Ended up writing a scope for this like so:
public function scopeAvail($query)
{
return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
}
And then call:
Items::avail()->get();
Works for now, but a bit messy. Would like to see something with a keyword like not:
Auth::user()->itemsNot();
Basically Eloquent is running the above query anyway, except with a = instead of a <>.

Maybe you can use:
DB::table('users')
->whereExists(function($query)
{
$query->select(DB::raw(1))
->from('orders')
->whereRaw('orders.user_id = users.id');
})
->get();
Source: http://laravel.com/docs/4.2/queries#advanced-wheres

This code brings the items that have no relationship with the user.
$items = $this->item->whereDoesntHave('users')->get();

Related

how to use whereHas in laravel

I am new to laravel,
I need to create a query for the db,
$query = Deal::query();
I want to use the wherehas operator.
this is my code that is worked.
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus);
// \Log::info('The request precedence: '.$precedenceStatus);
}
I want to add this code also to the query
if($person) {
$query->whereHas('personnel', function ($subQuery) use ($person) {
$subQuery->where('id', '=', $person);
});
}
So I need to change the first code?
how I can convert the first code to wherehas?
the first code is from table called deal, the second section is from realtionship called personnel.
the second section worked in other places in the code, I just need to fix the first section and not understand what to write in the use
I try this and get error on the last }
else if ($group_by == 'precedence') {
if($get_deals_for == 'noprecedence'){
$get_deals_for = 0;
}
$precedenceStatus = $get_deals_for;
$query-> where('precedence', '=', $precedenceStatus)
-> when ($person, function($query) use($person) {
$query->whereHas('personnel', function ($query) use ($person) {
$query->where('id', '=', $person);
});
})
}
There is a method you can use called when(, so that you can have cleaner code. The first parameter if true will execute your conditional statement.
https://laravel.com/docs/9.x/queries#conditional-clauses
$result = $query
->where('precedence', '=', $precedenceStatus)
->when($person, function ($query) use ($person) {
$query->whereHas('personnel', fn ($q) => $q->where('id', '=', $person));
})
->get();
You should also be able to clean up your precedence code prior to that using when( to make the entire thing a bit cleaner.
Querying to DB is so easy in laravel you just need to what you want what query you want execute after that you just have to replace it with laravel helpers.Or you can write the raw query if you cant understand which function to use.
using,DB::raw('write your sql query').
Now Most of the time whereHad is used to filter the data of the particular model.
Prefer this link,[Laravel official doc for queries][1] like if you have 1 to m relation ship so u can retrive many object from one part or one part from many object.like i want to filter many comments done by a user,then i will right like this.
$comments = Comment::whereHas('user', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
$comments = Here will be the model which you want to retrive::whereHas('relationship name', function (Builder $query) {
$query->where('content', 'like', 'title%');
})->get();
you can also write whereHas inside whereHas.
[1]: https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence

Joining 2 scopes laravel

I've been trying to solve this for quite a while now. I want to join these two scopes from my Match Model:
public function scopeMainMatches($query)
{
return $query->where('type', 'main');
}
public function scopeDotaMatches($query)
{
return $query->join('leagues', function ($join) {
$join->on('matches.league_id', '=', 'leagues.id')
->select('matches.*')
->where('leagues.type', '=', 'dota2')
->where('matches.type', '=', 'main');
});
}
so basically, when I put in into join eloquent relationship it will be the same like this:
$query = DB::table('matches')
->join('leagues', 'leagues.id', '=', 'matches.league_id')
->select('matches.*')
->where('leagues.type', '=', 'dota2')
->get();
it works fine during the terminal check. but I need to connect 2 scopes for the Controller which looks like this:
$_matches = \App\Match::mainMatches()
->get()
->load('teamA', 'teamB')
->sortByDesc('schedule');
so when I try to connect mainMatches and dotaMatches, it doesn't show up on the matches. although when i run php artisan tinker, it returns the correct output, but it won't show up on the matches table.
$_matches = \App\Match::mainMatches()
->dotaMatches()
->get()
->load('teamA', 'teamB')
->sortByDesc('schedule');
any Ideas how to work on this? TYIA!
I've managed to join two tables in just one scope here is the code:
public function scopeMainMatches($query) {
return $query->join('leagues','leagues.id','=','matches.league_id')->select('matches.*')->where('matches.type', 'main');
}

october cms (laravel) where query

I have a some problem with filter query. I need to do somethink like
select painting from artist_painting where type=$_GET['type'] AND material=$_GET['material'] and artist_slug =$_GET['artist_slug'] ORDER BY painting DESC
I have a pivot table artist_painting and artist. 'artist_slug' is in the 'artist' table
I do
$this['painting'] = Painting::whereHas('artist', function($q)
{
$q->where('artist_slug', '=', $this->param('slug'));
})->get();
but I do not know what to do next.
How can i do query in php code?
Short and dirty:
Painting::where('type',input("type"))
->where('material',input("material"))
->whereHas('artist', function($q)
{
$q->where('artist_slug', '=', $this->param('slug'));
})->get();
The explanation:
When you initialize a query a query builder instance is returned. Basically all methods on the query builder return the same instance so you can daisy chain them into one query.
But you can also just work on the query builder.
$query = Painting::where('type',input("type"));
or:
$query = $model->newQuery()// Where model is an intance of painting, for example new Painting();
Then you can just work on the query builder instance, pass it to other methods that might to do things.
function getPaintings($type, $material, $slug)
{
$query = Painting::where('type',$type);
$query->where('material', $material);
$this->findArtistBySlug($query, $slug);
return $query->get()
}
function findArtistBySlug($query, $slug)
{
$query->whereHas('artist', function($q) use ($slug)
{
$q->where('artist_slug', '=', $slug);
});
$query->with(['artist']);
}
You might want to read https://octobercms.com/docs/database/query
and https://laravel.com/docs/5.6/queries
I would solve this problem from the Artist's point of view:
$artist = Artists::where('artist_slug', $this->param('slug'))->with('paintings')->first();
All the paintings of the artist can be accessed by using $artist->paintings, which will be a Collection.

Sort collection by relationship value

I want to sort a laravel collection by an attribute of an nested relationship.
So I query all projects (only where the project has tasks related to the current user), and then I want to sort the projects by deadline date of the task relationship.
Current code:
Project.php
public function tasks()
{
return $this->hasMany('App\Models\ProjectTask');
}
Task.php
public function project()
{
return $this->belongsTo('App\Models\Project');
}
UserController
$projects = Project->whereHas('tasks', function($query){
$query->where('user_id', Auth::user()->id);
})->get()->sortBy(function($project){
return $project->tasks()->orderby('deadline')->first();
});
I don't know if im even in the right direction?
Any advice is appreciated!
A nice clean way of doing this is with the . operator
$projects = Project::all()->load('tasks')->sortBy('tasks.deadline');
I think you need to use something like join() and then sort by whatever you need.
For exapmle:
Project::join('tasks', 'tasks.project_id', '=', 'projects.id')
->select('projects.*', DB::raw("MAX(tasks.deadline) as deadline_date"))
->groupBy('tasks.project_id')
->orderBy('deadline_date')
->get()
Update
Project::join('tasks', function ($join) {
$join->on('tasks.project_id', '=', 'projects.id')
->where('tasks.user_id', Auth::user()->id)
->whereNull('tasks.completed');
})
->select('projects.*', DB::raw("MAX(tasks.deadline) as deadline_date"))
->groupBy('tasks.project_id')
->orderBy('deadline_date')
->get()
Update2
Add with in your query as:
->with(['tasks' => function ($q) {
$q->where('user_id', Auth::user()->id)
->whereNull('completed');
})
Try This,
$tasks = Task::with('project')
->where('user_id',Auth::user()->id)
->orderBy('deadline')
->get();
After that you can access project properties like below
$tasks->first()->project()->xxx

Eloquent / Laravel - Putting a WHERE Clause on a Reference Table With Chained Relationships

I have the following relationship functions in my Job model:
public function resourceTypes(){
return $this->belongsToMany('ResourceType', 'job_requests');
}
public function resources(){
return $this->belongsToMany('Resource', 'jobs_resources')->withPivot('flow_type', 'resource_type_id');
}
I am able to get an object with data from both of the above relationships using:
$job = Job::findorfail($projectId);
$result = $job->with('resources.resourceTypes')->get();
I would like to put a where clause on the jobs_resources pivot table - specifically on the column flow_type.
How would I do this?
Try something like this:
$job = Job::with('resources' => function($q) {
$q->with('resourceTypes')->where('flow_type',2);
})->findorfail($projectId);
In above you will get only those resources with flow_type = 2
I ended up using the following statement:
Job::with(['resources' => function ($query){
$query->wherePivot('flow_type', '=', '1' );
}, 'resources.resourceTypes'])->where('id', $projectId)->firstOrFail();
$result = DB::table('job')
->join('job_resources', 'job.id', '=', 'job_resources.job_id')
->join('job_requests', 'job_resources.request_id', '=', 'job_requests.id')
->where('job_resources.flow_type', '=', CONDITION)
->get();
Your table data is not clear from your input, but this method (query builder) should work

Resources