Laravel красноречивая группа по связи hasMany - PullRequest
1 голос
/ 28 февраля 2020

У меня есть users и user_positions таблица.

Модель пользователя

public function positions()
{
    return $this->hasMany(UserPosition::class);
}

Пример данных:

Пользователи:

----------------
| id | name    |
----------------
| 1  | Alex    |
| 2  | Nick    |
| 3  | John    |
| 4  | Liam    |
| 5  | Noah    |
| 6  | William |
| 7  | James   |
| 8  | Oliver  |
| 9  | Benjamin|
| 10 | Elijah  |
| 11 | Lucas   |
----------------

Пользователи Позиции

------------------------
|  position  | user_id |
------------------------
| Developer  |   1     |
| Designer   |   2     |
| Teacher    |   1     |
| Singer     |   3     |
| Architect  |   3     |
| Accountant |   4     | 
| Baker      |   2     |
| Actress    |   7     |
| Chef       |   11    |
| Butcher    |   10    |
| Carpenter  |   8     |
| Developer  |   9     |       
| Accountant |   11    |       
| Butcher    |   8     |  
| Singer     |   10    |  
| Carpenter  |   7     |   
| Carpenter  |   1     |   
------------------------

В этом случае, как я могу сгруппировать пользователя по названию позиции и получить такой результат:

[
    Developer => [1, 9],
    Designer => [2],
    Teacher => [1],
    Singer => [3, 10],
    Architect => [3],
    Accountant => [4, 11],
    Baker => [2],
    Actress => [7],
    Chef => [11],
    Butcher => [10, 8],
    Carpenter => [8, 7, 1]
]

Ответы [ 5 ]

1 голос
/ 28 февраля 2020

Мне нравится ответ Седева, но чтобы получить нужные ключи, вы можете попробовать поработать с полученным Eloquent \ Collection.

UserPosition::where(...)->get()
    ->groupBy('position')->map(function (array $groupedPositions) {
        return collect($groupedPositions)->pluck('id');
    });

Это немного отличается в этом, как только вы звоните get(), вы говорите с объектом Collection, а не с Query \ Builder. Это означает, что последующий вызов groupBy() будет , а не тем же, который в противном случае отфильтровал бы результаты запроса, но вместо этого вложил их. Это дает методу map() доступ ко всем данным, которые ему необходимы для организации, как вы описали.

1 голос
/ 28 февраля 2020

Вы ищете отношения многих ко многим. Если вы используете среднюю сводную таблицу в соответствии с документацией Laravel , вы можете легко изменить поиск.

Сейчас у вас есть пользователи, у которых много позиций, но у вас нет структуры, которую легко получить все пользователи в определенной позиции, так как позиции повторяются в вашей дополнительной таблице.

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

1 голос
/ 28 февраля 2020

Попробуйте это:

$data = UsersPosition::selectRaw("position, GROUP_CONCAT('user_id')")
                     ->groupBy('position')
                     ->get();
1 голос
/ 28 февраля 2020

Поскольку mysql не может предоставить вам ассоциативный массив, вы должны использовать функцию GROUP_CONCAT. Если у вас есть пользователь, например $user = Auth::user(), и вы получаете $user->positions, вы получите все позиции для одного пользователя.

Если вы хотите получить сгруппированные данные для каждой позиции, вы должны выполнить следующий код:

UserPosition::query()
    ->selectRaw('
        position,
        GROUP_CONCAT(user_id) as users
    ')
    ->groupBy('user_id')
    ->get()
    ->map(function($val){
        $val->users = explode(',', $val->users);
    })
    ->pluck('users', 'position')
    ->toArray();

И вы получите массив, который хотите

1 голос
/ 28 февраля 2020

Вы можете использовать GROUP_CONCAT для того же:

$data = UsersPosition::selectRaw("position, GROUP_CONCAT('user_id')")
->groupBy('position')
->get();

https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group -concat

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...