Создание многомерной структуры из сгруппированных агрегатных данных из запроса Eloquent

Я хочу создать вложенный объект JSON, примерно так:

[
    {
        "age": 8,
        "countAll": 3,
        "gender": [
            {
                "genderName": "male",
                "countGender": 2
            },
            {
                "genderName": "female",
                "countGender": 1
            },
        ]
    },
    {
        "age": 10,
        "countAll": 1,
        "gender": [
            {
                "genderName": "male",
                "countMale": null (or "0")
            },
            {
                "genderName": "female",
                "countFemale": 1
            },
        ]
    },

У меня есть одна таблица в MySQL:

| id | name     |  gender  | age | user_id | 
--------------------------------------------
| 1  | nameA    | male     | 8   |    1    |
| 2  | nameB    | female   | 10  |    1    |
| 3  | nameC    | male     | 8   |    1    |
| 4  | nameD    | female   | 8   |    1    |

Я использую laravel 10, это запрос, который я сделал

$test = Participant::select('age', DB::raw('COUNT(age) as countAge'), DB::raw('COUNT(gender) as  countGender'))->where('user_id', $user_id)->groupBy('age')->orderBy('age', 'ASC')->get();
$output = array();
$currentAge = "";
$currentCount = "";

foreach ($test as $data) {
   if ($data->age != $currentAge) {
      $output[] = array();

      end($output);
      $currentItem = &$output[key($output)];
      $currentAge = $data->age;
      $currentCount = $data->countAge;
      $currentItem['age'] = $currentAge;
      $currentItem['countAll'] = $currentCount;
      $currentItem['gender'] = array();
    }
    $currentItem['gender'][] = array('genderName' => $data->gender, 'countGender' => $data->countGender);
}

и результат json_encoded:

[
    {
        "age": 8,
        "countAll": 3,
        "gender": [
            {
                "genderName": null,
                "countGender": 3
            }
        ]
    },
    {
        "age": 10,
        "countAll": 1,
        "gender": [
            {
                "genderName": null,
                "countGender": 1
            }
        ]
    },

Я прочитал много ссылок о создании вложенного JSON и внес много изменений в запрос SQL, но пока не нашел решения.

Как я могу заставить этот запрос Eloquent возвращать вложенный объект JSON, подобный тому, который я описал выше?

Поскольку mysql является реляционной базой данных, она может возвращать только простой табличный вывод. Использование красноречия не меняет этого. Вам либо нужно довольствоваться табличным выводом из базы данных, либо вам нужно выполнить некоторую обработку пост-запроса в вашем PHP-коде, чтобы получить желаемый результат.

Shadow 25.06.2024 07:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
2
75
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Нечто подобное можно сделать, как показано ниже:

$participants = Participant::select('age')
    ->selectRaw('COUNT(*) as countAll')
    ->selectRaw('SUM(CASE WHEN gender = "male" THEN 1 ELSE 0 END) as countMale')
    ->selectRaw('SUM(CASE WHEN gender = "female" THEN 1 ELSE 0 END) as countFemale')
    ->where('user_id', $user_id)
    ->groupBy('age')
    ->orderBy('age', 'ASC')
    ->get();

$result = [];

foreach ($participants as $participant) {
    $genderData = [
        [
            'genderName' => 'male',
            'countGender' => $participant->countMale ?? 0,
        ],
        [
            'genderName' => 'female',
            'countGender' => $participant->countFemale ?? 0,
        ]
    ];

    $result[] = [
        'age' => $participant->age,
        'countAll' => $participant->countAll,
        'gender' => $genderData,
    ];
}

$jsonOutput = json_encode($result);

Пожалуйста, не публикуйте ответы, содержащие только код, в Stack Overflow.

mickmackusa 25.06.2024 05:33
Ответ принят как подходящий

Я считаю, что желаемая структура вывода немного громоздка. Возможно, было бы разумнее объявить более глубокие точки данных, специфичные для пола, более простыми ассоциативными элементами genderCounts => ['male' => 2, 'female' => 1]. Фактически, чтобы избежать свертки вызовов методов сбора в наборе результатов, вам следует свести желаемый результат к двумерной структуре, чтобы его можно было достичь исключительно с помощью SQL.

Код: (Демо-версия PHPize)

$user_id = 1;

var_export(
    DB::table('Participant')
    ->select('age')
    ->selectRaw('COUNT(1) total')
    ->selectRaw("SUM(gender = 'male') male")
    ->selectRaw("SUM(gender = 'female') female")
    ->where('user_id', $user_id)
    ->groupBy('age')
    ->orderBy('age', 'ASC')
    ->get()
    ->toArray()
);

чтобы подготовить эти агрегированные данные с помощью метода сбора Laravel, просто добавьте map() после вызова get(). (Демо-версия PHPize)

->map(fn($row) => [
    'age' => $row->age,
    'countAll' => $row->total,
    'gender' => [
        ['genderName' => 'male', 'countMale' => $row->male],
        ['genderName' => 'female', 'countFemale' => $row->female]
    ]
])

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