Where NOT in pivot table

前端 未结 7 1735
栀梦
栀梦 2020-12-13 19:02

In Laravel we can setup relationships like so:

class User {
    public function items()
    {
        return $this->belongsToMany(\'Item\');
    }
}


        
相关标签:
7条回答
  • 2020-12-13 19:08

    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); 
    
    0 讨论(0)
  • 2020-12-13 19:11

    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();
    
    0 讨论(0)
  • 2020-12-13 19:20

    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();
    
    0 讨论(0)
  • 2020-12-13 19:23

    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();
    
    0 讨论(0)
  • 2020-12-13 19:27

    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.

    0 讨论(0)
  • 2020-12-13 19:27

    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 <>.

    0 讨论(0)
提交回复
热议问题