通过pivot表检查数据库中是否存在关系

ekqde3dh  于 2021-06-20  发布在  Mysql
关注(0)|答案(4)|浏览(405)

情况
用户可以属于多个组织,通过名为 employees 游戏中的模特: User , Employee & Organizations 相关数据库列:

users
- id

employees
- user_id
- organization_id

organizations
- id

目标
一种检查用户 1 和用户 2 至少共享一个 organization_idemployees table
使用案例
api终结点 /api/v1/user/# 返回有关用户的其他元数据。
使用 policy ,它将检查当前用户和url中的用户id是否相同,或者它们是否都是至少一个组织中的员工 organization_id 目前还不知道,重要的是它是否匹配。
示例a
用户a( 1 )是组织的雇员吗( 1 )
用户b( 2 )是组织吧的员工吗( 2 )
因此,employee表具有以下记录:

+-----------------+---------+
| organization_id | user_id |
+-----------------+---------+
|               1 |       1 |
|               2 |       2 |
+-----------------+---------+

在本例中,查询应该返回一个假结果,因为没有共享的 organization_id 在用户a和b之间
例b
用户a( 1 )是组织的雇员吗( 1 )
用户a( 1 )是组织foobar的员工吗( 3 )
用户b( 2 )是组织吧的员工吗( 2 )
用户b( 2 )是组织foobar的员工吗( 3 )
因此,employee表具有以下记录:

+-----------------+---------+
| organization_id | user_id |
+-----------------+---------+
|               1 |       1 |
|               2 |       2 |
|               3 |       1 |
|               3 |       2 |
+-----------------+---------+

在本例中,查询应该返回一个true结果,因为存在一个共享的 organization_id 在用户a和b之间
保单代码

/**
 * Determine whether the user can view the model.
 *
 * @param  \App\User  $user
 * @param  \App\User  $model
 * @return mixed
 */
public function view(User $user, User $model)
{
    if ($user->is($model)) {
        return true;
    } else {
        // check if users share at least one organization 
    }
}

有效但看起来效率不高的代码

foreach ($user->organizations()->with('users')->get() as $organization) {

    if ($organization->users->where('id', $model->id)->first()) {
        return true;
    }

}

return false;

使用连接而不是使用laravel模型的实验代码

\Illuminate\Support\Facades\DB::table('employees as auth_employee')
        ->join('employees as other_employee', 'other_employee.organization_id', '=', 'auth_employee.organization_id')
//        ->join('organizations', 'organizations.id', '=', 'organizations.id')
        ->where('auth_employee.id', 1)
        ->where('other_employee.id', 2)
        ->get()

请求的解决方案
一个有效的查询,无论两个用户是否至少共享一个布尔结果 organization_idemployees 表:使用laravel模型/查询生成器的“加分”。
页脚
谢谢你的阅读,这里有一个土豆:?

wlzqhblo

wlzqhblo1#

假设你在你的网站上建立了一个用户关系 Organization 模型,可以使用wherehas方法:

$user->organizations()->whereHas('users', function ($query) use($model) {
    $query->where('users.id', $model->id);
})->exists();
cl25kdpy

cl25kdpy2#

要检查用户1和2是否共享一个或多个组织,请执行以下操作:

SELECT EXISTS (
          SELECT 1 FROM employees AS a
                   JOIN employees AS b  USING(organization_id)
                   WHERE  a.user_id = 1
                     AND  b.user_id = 2;

具有以下两个索引:

(user_id, organization_id)
(organization_id, user_id)
vulvrdjw

vulvrdjw3#

作为原始查询,我可能会使用 EXISTS 在这里,由于您需要将任何查询移植到laravel/php代码,我建议您使用self-join:

SELECT DISTINCT
    e1.user_id, e2.user_id
FROM employees e1
INNER JOIN employees e2
    ON e1.organization_id = e2.organization_id AND e1.user_id = 2
WHERE
    e1.user_id = 1;

这只会返回 user_id 一对值 (1, 2) . 如果希望查询返回至少共享一个组织的所有不同用户对,可以将此查询重写为:

SELECT DISTINCT
    e1.user_id, e2.user_id
FROM employees e1
INNER JOIN employees e2
    ON e1.organization_id = e2.organization_id AND e1.user_id <> e2.user_id;
h22fl7wq

h22fl7wq4#

我能想到的最具可读性的例子是在用户模型中加入这样的内容:

public function isColleagueWith(User $user): bool
{
    return $this->organizations->intersectByKey($user->organizations)->count() > 0;
}

用法易于阅读和理解:

$userA->isColleagueWith($userB);

如果希望使用较少的db查询,可以直接查询pivot表。在这里,您可以获取使用这两个用户的所有组织,并检查列表是否包含任何重复的组织id。

use Illuminate\Database\Eloquent\Relations\Pivot;

class Employees extends Pivot
{
    public function areColleagues(int $userIdA, int $userIdB): bool
    {
        $employments = $this->where('user_id', $userIdA)
            ->orWhere('user_id', $userIdB)
            ->get('organization_id');

        return $employments->count() > $employments->unique()->count();
    }
}

用法:

Employees::areColleagues($userIdA, $userIdB);

相关问题