最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Filter Laravel Eloquent Query with relationship based on having multiple many-to-many-relationships - Stack Overflow

programmeradmin3浏览0评论

I have Tasks that have many-to-many relationships with Locations. I want the user to be able to select "home" and "work" as an example out of a list of locations and then a toggle switch for AND vs OR where switched between these two behaviours: 1-AND All tasks if they have any labels that is either HOME or WORK or BOTH will all be loaded. (This is working perfectly in my code) 2-OR(BAD LABEL BUT JUST TRYING TO GET IT TO WORK) All tasks that have both labels attached and only both will be loaded. Not if they only have one.

Below is my code where the 2nd requirement is not working and returns and empty list when there are results to be returned.

return \App\Models\Task::query()
            ->with('locations')
            ->with('tags')
            ->with('ai')
            ->with('entities')
            ->with('delegatee')
            ->with('event')
            ->with('time')
            ->tap(function ($query) {
                if($this->where) {
                    $query->whereHas('locations', function($q)
                    {
                        if($this->where_method=="AND"){ 
                            $q->whereIn(  'locations.slug', $this->where );
                        }else { 
                            $q->where(function($query) {
                                foreach($this->where as $where) {
                                    $query->where('locations.slug', $where );
                                } 
                            });
                        }
                    
                    });
                } 
                if($this->sortBy) {
                    return $query->orderBy($this->sortBy, $this->sortDirection);
                 }else { 
                    return $query;
                 }
            }) 
            ->paginate($this->per_page);

My only idea is that the hasWhere closure only joins one instance of Location as random to check if there is any location or not and so the where filter located in the wrong place in query will never see both and only one joined during that where clause? Its a livewire component and a little tricky to see my computer query but I will dig in to see if thats more helpful and copy it here.

I have Tasks that have many-to-many relationships with Locations. I want the user to be able to select "home" and "work" as an example out of a list of locations and then a toggle switch for AND vs OR where switched between these two behaviours: 1-AND All tasks if they have any labels that is either HOME or WORK or BOTH will all be loaded. (This is working perfectly in my code) 2-OR(BAD LABEL BUT JUST TRYING TO GET IT TO WORK) All tasks that have both labels attached and only both will be loaded. Not if they only have one.

Below is my code where the 2nd requirement is not working and returns and empty list when there are results to be returned.

return \App\Models\Task::query()
            ->with('locations')
            ->with('tags')
            ->with('ai')
            ->with('entities')
            ->with('delegatee')
            ->with('event')
            ->with('time')
            ->tap(function ($query) {
                if($this->where) {
                    $query->whereHas('locations', function($q)
                    {
                        if($this->where_method=="AND"){ 
                            $q->whereIn(  'locations.slug', $this->where );
                        }else { 
                            $q->where(function($query) {
                                foreach($this->where as $where) {
                                    $query->where('locations.slug', $where );
                                } 
                            });
                        }
                    
                    });
                } 
                if($this->sortBy) {
                    return $query->orderBy($this->sortBy, $this->sortDirection);
                 }else { 
                    return $query;
                 }
            }) 
            ->paginate($this->per_page);

My only idea is that the hasWhere closure only joins one instance of Location as random to check if there is any location or not and so the where filter located in the wrong place in query will never see both and only one joined during that where clause? Its a livewire component and a little tricky to see my computer query but I will dig in to see if thats more helpful and copy it here.

Share Improve this question asked Feb 17 at 1:53 NeoNeo 11.6k3 gold badges71 silver badges81 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

It was a lot easier than what I had written:

if($this->where) {
                $q->whereHas('locations', function($q)
                {   
                        $q->whereIn( 'locations.slug', $this->where );  
                }, '>=', $this->where_method=="OR"?1:count($this->where));
            } 

The extra parameters of whereHas is exactly what I needed, you can specify an operator and count value to further customize the query::

whereHas($queryStuff, '>=', $this->where_method=="OR"?1:count($this->where));

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论