Проверьте, существует ли связь в базе данных через сводную таблицу

ситуация

Пользователь может принадлежать к нескольким организациям, связанным с помощью сводной таблицы employees.

Модели в действии: User, Employee и Organizations

Соответствующие столбцы базы данных:

users
- id

employees
- user_id
- organization_id

organizations
- id

Цель

Эффективный способ проверить, разделяют ли пользователь 1 и пользователь 2 хотя бы один organization_id в таблице employees.

вариант использования

Конечная точка Api /api/v1/user/# возвращает дополнительные метаданные о пользователе.

Используя policy, он проверяет, совпадают ли текущий пользователь и идентификатор пользователя из URL-адреса, или они оба являются сотрудниками по крайней мере в одной организации, organization_id на этом этапе неизвестен, все, что имеет значение, это то, что он совпадает.

пример А

пользователь A (1) является сотрудником организации foo (1)

пользователь B (2) является сотрудником организационной панели (2)

Таким образом, таблица сотрудников содержит следующие записи:

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

в этом примере запрос должен возвращать ложный результат, поскольку между пользователем A и B нет общего organization_id.

пример B

пользователь A (1) является сотрудником организации foo (1)

пользователь A (1) является сотрудником организации foobar (3)

пользователь B (2) является сотрудником организационной панели (2)

пользователь B (2) является сотрудником организации foobar (3)

Таким образом, таблица сотрудников содержит следующие записи:

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

в этом примере запрос должен возвращать истинный результат, поскольку существует общий 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()

запрошенное решение

Эффективный запрос для получения (с возможностью преобразования в) логического результата, если 2 пользователя используют хотя бы один organization_id в таблице employees, «бонусные баллы» за использование моделей / построителя запросов laravel.

нижний колонтитул

Спасибо, что прочитали, вот картошка: ?

Спасибо за картошку, но вы можете сообщить нам, что вы хотите здесь? Вы хотите, чтобы необработанный запрос MySQL решил вашу проблему, хотите ли вы код Laravel / PHP или что-то еще?

Tim Biegeleisen 07.09.2018 12:50

Предпочтительно запрос mysql в формате построителя запросов laravel или как отношение модели @TimBiegeleisen

Quezler 07.09.2018 12:53

как насчет того, чтобы взять весь идентификатор организации у обоих пользователей и проверить метод php in_array? разве это не будет решением? поскольку вам не нужен идентификатор организации, этого будет достаточно, верно?

Jithin 07.09.2018 12:57

Не могли бы вы показать нам результат точный, который вы хотите получить из этого запроса, в терминах значений?

Tim Biegeleisen 07.09.2018 12:57

@KevinRED это вариант, но в настоящее время я ищу сделать это как запрос, чтобы не втягивать много данных из базы данных.

Quezler 07.09.2018 12:58

@Quezler, хорошо, понял

Jithin 07.09.2018 12:59

@TimBiegeleisen - вывод, который можно интерпретировать как логическое значение, например массив событий, которые могут быть count() > 0ed

Quezler 07.09.2018 13:00

Я попытался ответить ниже в необработанном MySQL; посмотри.

Tim Biegeleisen 07.09.2018 13:02

@TimBiegeleisen спасибо за этот ответ, прежде чем я помечу его как принятый, я планирую подождать еще немного, чтобы увидеть, будет ли добавлен более laravel-ish ответ, но я буду голосовать за него заранее ?

Quezler 07.09.2018 13:04

Просто чтобы дважды проверить, вы хотите увидеть, разделяют ли $user и $model одну организацию, или просто пользователь разделяет организацию с кем-то еще?

Rwd 07.09.2018 13:10

@RossWilson, чтобы узнать, связан ли $user с $model через общий organization_id в таблице employees, но идентификатор organization не известен во время запроса, все, что имеет значение, это то, что они оба являются частью по крайней мере одной организации, что они оба сотрудник

Quezler 07.09.2018 13:12
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
3
11
1 102
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

В качестве необработанного запроса я, вероятно, использовал бы здесь EXISTS, но, поскольку вам нужно будет перенести любой запрос в код Laravel / PHP, я мог бы предложить использовать самосоединение:

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;
Ответ принят как подходящий

Предполагая, что в вашей модели Organization настроены отношения пользователей, вы можете использовать метод где:

$user->organizations()->whereHas('users', function ($query) use($model) {
    $query->where('users.id', $model->id);
})->exists();
Integrity constraint violation: 1052 Column 'id' in where clause is ambiguous
Quezler 07.09.2018 13:20

@Quezler Я обновил свой ответ, включив имя таблицы в предложение where.

Rwd 07.09.2018 13:21

Работает как шарм, но выполняет ли он только один запрос или повторяет обратный вызов для каждого пользователя и т. д. В базе данных?

Quezler 07.09.2018 13:23

@Quezler Это будет всего лишь один запрос.

Rwd 07.09.2018 13:48

Самый читаемый пример, который я могу придумать, - это добавить что-то вроде этого в пользовательскую модель:

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

Использование легко читать и понимать:

$userA->isColleagueWith($userB);

Если вы хотите использовать меньше запросов к БД, вы можете вместо этого напрямую запросить сводную таблицу. Здесь вы можете получить все организации, в которых работают два пользователя, и проверить, содержит ли список повторяющиеся идентификаторы организаций.

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

Если у вас уже есть пользователи, это всего лишь один дополнительный запрос, чтобы получить и организации, нетерпеливо загрузив отношение организаций, поэтому вы можете легко использовать решение № 1. Если у вас только два идентификатора пользователя, это проще с решением № 2 .

Torkil Johnsen 07.09.2018 13:46

Чтобы проверить, принадлежат ли пользователи 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)

Другие вопросы по теме