【问题标题】:Where NOT in pivot table不在数据透视表中的位置
【发布时间】:2013-11-20 07:25:18
【问题描述】:

在 Laravel 中,我们可以这样设置关系:

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

允许我们为用户获取数据透视表中的所有项目:

Auth::user()->items();

但是,如果我想得到相反的结果怎么办。并获取用户还没有的所有项目。所以不在数据透视表中。

有没有简单的方法来做到这一点?

【问题讨论】:

  • 以下来自 Wallace Maxters (stackoverflow.com/a/27742997/2111952) 的答案现在似乎是正确答案。 Laravel 现在有 whereDoesntHave - 不确定在最初提出问题时是否有。

标签: laravel laravel-4 pivot-table eloquent


【解决方案1】:

查看Illuminate\Database\Eloquent\Builder类的源代码,我们在Laravel中有两个方法可以做到这一点:whereDoesntHave(与whereHas相反)和doesntHave(与@相反) 987654326@)

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

这对我来说是正确的!

对于简单的“不存在关系”,请使用:

User::doesntHave('Role')->get();

对不起,不懂英文。我用的是谷歌翻译器。

【讨论】:

  • 这里是 API 文档中 whereDoesntHave 的链接:laravel.com/api/5.0/Illuminate/Database/Eloquent/…Wallace 似乎找到了最佳答案(也许之前没有)
  • 没错!只是我在源代码中发现了激动人心的东西(就像我一直做的那样)。我当时不知道 Laravel 5
【解决方案2】:

为了简单和对称,您可以在用户模型中创建一个新方法:

// User model
public function availableItems()
{
    $ids = \DB::table('item_user')->where('user_id', '=', $this->id)->lists('user_id');
    return \Item::whereNotIn('id', $ids)->get();
}

使用调用:

Auth::user()->availableItems();

【讨论】:

  • 实际上最终采用了这个解决方案。如果数据透视表为空,我自己发布的答案将不起作用。
  • 根据 Laravel 文档,availableItems 应该是 scopeAvailableItems
  • 确实,问题应该用版本号标记。我相信它是 v4.0 或 v4.1
  • 在 Laravel 5.5+ 中,您可以将 -&gt;lists('user_id') 方法替换为 -&gt;pluck('user_id)
【解决方案3】:

这不是那么简单,但通常最有效的方法是使用子查询。

$items = Item::whereNotIn('id', function ($query) use ($user_id)
    {
        $query->select('item_id')
            ->table('item_user')
            ->where('user_id', '=', $user_id);
    })
    ->get();

如果这是我经常做的事情,我会将其作为范围方法添加到 Item 模型中。

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

}

然后像这样使用它。

$items = Item::whereNotRelatedToUser($user_id)->get();

【讨论】:

  • 这看起来很有趣,但是我猜它正在运行额外的查询来获取项目列表?
  • 它编译成一个子查询,所以它只是对数据库的一个请求。 dev.mysql.com/doc/refman/5.0/en/subqueries.html
  • 我正在使用 laravel 5 并且不得不将 -&gt;table 替换为 -&gt;from。否则我会得到一个 BadMethodCallException 调用未定义的方法 Illuminate\Database\Query\Builder::table()
【解决方案4】:

左连接怎么样?

假设这些表是usersitemsitem_user,找出所有与用户123无关的items

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

【讨论】:

    【解决方案5】:

    这应该适合你

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

    【讨论】:

      【解决方案6】:

      最终像这样为此编写了一个范围:

      public function scopeAvail($query)
      {
          return $query->join('item_user', 'items.id', '<>', 'item_user.item_id')->where('item_user.user_id', Auth::user()->id);
      }
      

      然后调用:

      Items::avail()->get();
      

      暂时有效,但有点混乱。想看看像not这样的关键字:

      Auth::user()->itemsNot();
      

      基本上,Eloquent 无论如何都会运行上述查询,除了 = 而不是 &lt;&gt;

      【讨论】:

      • 您应该将 $user_id 传递到您的作用域中,而不是直接包含对 Auth::user() 的调用。
      【解决方案7】:

      也许你可以使用:

      DB::table('users')
              ->whereExists(function($query)
              {
                  $query->select(DB::raw(1))
                        ->from('orders')
                        ->whereRaw('orders.user_id = users.id');
              })
              ->get();
      

      来源:http://laravel.com/docs/4.2/queries#advanced-wheres

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-30
        • 1970-01-01
        • 1970-01-01
        • 2018-10-06
        • 2014-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多