Laravelは、多対多(同じユーザテーブル/モデル上):クエリは、指定したユーザーの関連含んするスコープ

PeraMika:

ユーザーがお互いをブロックすることができます。一のユーザは、ブロックすることができ、多くの(他の)ユーザーを、1人のユーザがによって遮断することができる多くの(他の)ユーザ。Userモデル私は、これらの持っている、多対多の関係を:

/**
 * Get the users that are blocked by $this user.
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function blockedUsers()
{
    return $this->belongsToMany(User::class, 'ignore_lists', 'user_id', 'blocked_user_id');
}

/**
 * Get the users that blocked $this user.
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function blockedByUsers()
{
    return $this->belongsToMany(User::class, 'ignore_lists', 'blocked_user_id', 'user_id');
}

ignore_listsピボットテーブルであり、それは持っているiduser_id'blocked_user_id'列)

私は、次の作成するクエリスコープ

1)ユーザーが含まれるようにされている指定されたユーザ(によってブロックを$id):

/**
 * Scope a query to only include users that are blocked by the specified user.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @param $id
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeAreBlockedBy($query, $id)
{
    // How to do this? :)
}

使用例: User::areBlockedBy(auth()->id())->where('verified', 1)->get();

2)しているユーザーに含まれない指定されたユーザ(によってブロックを$id):

/**
 * Scope a query to only include users that are not blocked by the specified user.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @param $id
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeAreNotBlockedBy($query, $id)
{
    // How to do this? :)
}

使用例: User::areNotBlockedBy(auth()->id())->where('verified', 1)->get();

3)ユーザーが含まれるようにブロックされた指定されたユーザを($id):

/**
 * Scope a query to only include users that blocked the specified user.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @param $id
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeWhoBlocked($query, $id)
{
    // How to do this? :)
}

使用例: User::whoBlocked(auth()->id())->where('verified', 1)->get();

4)ユーザー含めるにはブロックされませんでした指定されたユーザを($id):

/**
 * Scope a query to only include users that did not block the specified user.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @param $id
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeWhoDidNotBlock($query, $id)
{
    // How to do this? :)
}

使用例: User::whoDidNotBlock(auth()->id())->where('verified', 1)->get();


あなたはこれをどのように行うのでしょうか?私は中に何も見つかりませんでしたLaravelドキュメントこれについては(多分私はそれを逃しました)。(私が使用していますLaravel 6.xのを

私はわからないんだけど、私は、これは2つの方法で行うことができると思います:使用左が参加または使用して生のクエリをしてここ ...私は間違っているかもしれないが、私が思うにソリューションは限りのパフォーマンスとして良いだろう「左結合します」 、右懸念していますか?(これについてはよく分からない、多分私は完全に間違っています)。

Tsakhog:

使用join(inner join)パフォーマンスがより優れているwhereInサブクエリ。

MySQLでは、IN句内の副選択は、このように作成し、外部クエリ内のすべての行に対して再実行されますO(n^2)

私が使用することを考えるwhereHaswhereDoesntHave、クエリのために読みやすくなります。

1)関係法は、blockedUsers()すでにユーザーが含まれていますブロックされている指定されたことでuser ($id)、あなたは、このメソッドを直接使用することができました:

User::where('id', $id)->first()->blockedUsers();

適用について思いやりwhere('verified', 1)のようなクエリを使用することができますので、最初のUser::where('verified', 1)->areBlockedBy(auth()->id())範囲がこのようにすることができ、:

public function scopeAreBlockedBy($query, $id)
{
    return $query->whereHas('blockedByUsers', function($users) use($id) {
               $users->where('ignore_lists.user_id', $id);
           });
}

// better performance: however, when you apply another where condition, you need to specify the table name ->where('users.verified', 1)
public function scopeAreBlockedBy($query, $id)
{
    return $query->join('ignore_lists', function($q) use ($id) {
               $q->on('ignore_lists.blocked_user_id', '=', 'users.id')
                 ->where('ignore_lists.user_id', $id);
           })->select('users.*')->distinct();
}

私たちは、使用joinそれが使用する必要がないため、パフォーマンスが向上します2番目のクエリのためにwhere exists

ユーザーテーブル内の300,000レコードの例:

最初のクエリ説明whereHasスキャン301119+1+1行となります575mswhereHasを説明します whereHas回

2番目のクエリ説明joinスキャン3+1行となります10.1ms説明参加 時間に参加

2)ユーザーが含まれるようにすることによってブロックされていない指定されuser ($id)、あなたが使用することができwhereDoesntHave、この1のような閉鎖を:

public function scopeNotBlockedUsers($query, $id)
{
    return $query->whereDoesntHave('blockedByUsers', function($users) use ($id){
           $users->where('ignore_lists.user_id', $id);
     });
}

私が使用することを好むwhereDoesntHaveの代わりに、leftJoinここに。あなたが使用するときため、leftjoin以下のように:

User::leftjoin('ignore_lists', function($q) use ($id) {                                                            
     $q->on('ignore_lists.blocked_user_id', '=', 'users.id') 
       ->where('ignore_lists.user_id', $id);
})->whereNull('ignore_lists.id')->select('users.*')->distinct()->get();

Mysql need to create an temporary table for storing all the users' records and combine some ignore_lists.And then scan these records and find out the records which without ignore_lists. whereDosentHave will scan all users too. For my mysql server, where not exists is a little faster than left join. Its execution plan seems good. The performance of these two queries are not much different. whereDoesntHave説明 左nullの参加

For whereDoesntHave is more readable. I will choose whereDoesntHave. whereDoesntHaveとleftjoin

3) To include users that blocked the specified user ($id), to use whereHas blockedUsers like this:

public function scopeWhoBlocked($query, $id)
{
    return $query->whereHas('blockedUsers', function($q) use ($id) {
                $q->where('ignore_lists.blocked_user_id', $id);
           });
}

// better performance: however, when you apply another where condition, you need to specify the table name ->where('users.verified', 1)
public function scopeWhoBlocked($query, $id)
{
    return $query->join('ignore_lists', function($q) use ($id) {
               $q->on('ignore_lists.user_id', '=', 'users.id')
                 ->where('ignore_lists.blocked_user_id', $id);
           })->select('users.*')->distinct();
}

4) To include users that did not block the specified user ($id), use whereDoesntHave for blockedByUsers:

public function scopeWhoDidNotBlock($query, $id)
{
    return $query->whereDoesntHave('blockedUsers', function($q) use ($id) {
                $q->where('ignore_lists.blocked_user_id', $id);
           });
}

PS: Remember to add index on foreign_key for ignore_lists table.

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=372663&siteId=1