Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql Laravel多对多(在同一用户表/模型上):查询范围以包含指定用户的相关信息_Mysql_Laravel_Eloquent_Laravel Query Builder_Eloquent Relationship - Fatal编程技术网

Mysql Laravel多对多(在同一用户表/模型上):查询范围以包含指定用户的相关信息

Mysql Laravel多对多(在同一用户表/模型上):查询范围以包含指定用户的相关信息,mysql,laravel,eloquent,laravel-query-builder,eloquent-relationship,Mysql,Laravel,Eloquent,Laravel Query Builder,Eloquent Relationship,用户可以相互阻止。一个用户可以阻止多个(其他)用户,一个用户可以被多个(其他)用户阻止。 在User模型中,我有以下多对多关系: /** * Get the users that are blocked by $this user. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function blockedUsers() { return $this->belong

用户可以相互阻止。一个用户可以阻止多个(其他)用户,一个用户可以被多个(其他)用户阻止。 在
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\u lists
是透视表,它有
id
user\u id
“blocked\u user\u id”
列)

我想创建以下查询范围

1)包括被指定用户(
$id
)阻止的用户:

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

2)要包括指定用户(
$id
)未阻止的用户,请执行以下操作:

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

3)要包括阻止指定用户的用户(
$id
):

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

4)要包括未阻止指定用户的用户(
$id
):

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


你会怎么做? 我在网上找不到这方面的任何信息(也许我错过了)。 (我使用的是Laravel6.x)

我不确定,但我认为这可以通过两种方式来实现:使用左连接或在其中使用原始查询。。。我可能错了,但我认为“左连接”解决方案在性能方面会更好,对吗?(对此不确定,可能我完全错了)。

使用
连接(内部连接)
性能优于
其中的
子查询

在MySQL中,In子句中的子选择将针对外部查询中的每一行重新执行,从而创建
O(n^2)

我认为使用
whereHas
whereDoesntHave
进行查询会更具可读性

1) 关系方法
blockedUsers()
已经包含被指定的
用户($id)
阻止的用户,您可以直接使用此方法:

User::where('id',$id)->first()->blockedUsers();
首先考虑应用
where('verified',1)
,这样您就可以使用类似
User::where('verified',1)->areBlockedBy(auth()->id())
这样的查询,范围可以如下所示:

公共函数作用域被($query,$id)阻止
{
返回$query->whereHas('blockedByUsers',函数($users)use($id){
$users->where('ignore_lists.user_id',$id);
});
}
//更好的性能:但是,当应用另一个where条件时,需要指定表名->where('users.verified',1)
公共函数作用域被($query,$id)阻止
{
返回$query->join('ignore_list',函数($q)use($id){
$q->on('ignore_list.blocked_user_id'、'='、'users.id')
->其中('ignore_lists.user_id',$id);
})->选择('users.*')->distinct();
}
我们对第二个查询使用
join
,这将提高性能,因为它不需要在存在的地方使用

用户表中300000多条记录的示例: 解释第一个查询
whereHas
,该查询扫描
301119+1+1
行并获取
575ms

解释第二个查询
join
,它扫描
3+1
行并取
10.1ms

2) 要包含未被指定的
用户($id)
阻止的用户,您可以使用
whereDoesntHave
闭包,如下所示:

公共函数scopeNotBlockedUsers($query,$id)
{
返回$query->whereDoesntHave('blockedByUsers',函数($users)use($id){
$users->where('ignore_lists.user_id',$id);
});
}
我更喜欢使用
whereDoesntHave
而不是
leftJoin
。因为当您使用
leftjoin
时,如下所示:

User::leftjoin('ignore_list',函数($q)use($id){
$q->on('ignore_list.blocked_user_id'、'='、'users.id')
->其中('ignore_lists.user_id',$id);
})->whereNull('ignore_lists.id')->select('users.*')->distinct()->get();
Mysql需要创建一个临时表来存储所有用户的记录,并合并一些
忽略列表
,然后扫描这些记录,找出没有
忽略列表
的记录
whereDosentHave
也将扫描所有用户。对于我的mysql服务器,
where not exists
left join
快一点。它的执行计划似乎很好。这两个查询的性能差别不大。

对于
whereDoesntHave
更具可读性。我将选择
wheredonethave

3) 要包含阻止指定用户($id)
用户,请使用
其中有
阻止的用户,如下所示:

公共函数($query,$id)
{
返回$query->whereHas('blockedUsers',函数($q)use($id){
$q->where('ignore_list.blocked_user_id',$id);
});
}
//更好的性能:但是,当应用另一个where条件时,需要指定表名->where('users.verified',1)
公共函数($query,$id)
{
返回$query->join('ignore_list',函数($q)use($id){
$q->on('ignore_lists.user_id'、'='、'users.id')
->其中('ignore_lists.blocked_user_id',$id);
})->选择('users.*')
/**
 * 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? :)
}
/**
 * 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? :)
}
/**
 * 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? :)
}
/**
 * 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? :)
}
/**
 * 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)
{
    return User::whereHas('blockedByUsers', function($q) use($id) {
        $q->where('user_id', $id);
    });
}
User::areBlockedBy(auth()->id())->where('verified', 1)->get();
/**
 * 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)
{
    // It will exclude the user with $id
    return User::where('id', '!=', $id)
        ->whereDoesntHave('blockedByUsers', function($q) use($id) {
            $q->where('user_id', $id);
        });
}
User::areNotBlockedBy(auth()->id())->where('verified', 1)->get();
/**
 * 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)
{
    return User::whereHas('blockedUsers', function($q) use($id) {
        $q->where('blocked_user_id', $id);
    });
}
User::whoBlocked(auth()->id())->where('verified', 1)->get();
/**
 * 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)
{
    // It will exclude the user with $id
    return User::where('id', '!=', $id)
        ->whereDoesntHave('blockedUsers', function($q) use($id) {
            $q->where('blocked_user_id', $id);
        });
}
User::whoDidNotBlock(auth()->id())->where('verified', 1)->get();