Как я могу использовать фрагментированное кодирование передачи в Laravel?

Добрый день. Мне интересно, могу ли я использовать фрагментированное кодирование передачи (далее CTE) в ответе API? У меня большие данные в базе и мне нужно передать их клиенту одним запросом. Я много читал о механизме CTE, но не нашел, как это реализовать, к сожалению.

Одна важная вещь, которую следует упомянуть: отсутствие пагинации. Предполагается, что это автономная система, которая возвращает данные обратно на конечную точку клиента, а не на веб-страницу.

Как я уже говорил, данные хранятся в базе данных. Единственная проблема заключается в том, как разделить данные на сегменты (фрагменты) и отправить их в одном ответе API (один за другим).

Спасибо.


person Andrii H.    schedule 12.02.2019    source источник
comment
Я не совсем понимаю, какое отношение к проблеме имеет кодирование передачи по частям. Что вы подразумеваете под разделением данных на сегменты? С какими проблемами вы столкнулись, просто отправив весь набор результатов обратно? О каком именно количестве записей идет речь?   -  person Travis Britz    schedule 12.02.2019
comment
Например, он может содержать 10 записей, но у каждой есть поле json с более чем 100 000 записей.   -  person Andrii H.    schedule 12.02.2019
comment
Таким образом, было бы идеально передавать каждую запись одну за другой как кусок.   -  person Andrii H.    schedule 12.02.2019


Ответы (2)


В моем конкретном случае я решил свою проблему, используя этот код (пример):

use Symfony\Component\HttpFoundation\StreamedResponse;

$response = new StreamedResponse();
$response->setCallback(function () {
    var_dump('Hello World');
    flush();
    sleep(2);
    var_dump('Hello World');
    flush();
});
$response->send();
person Andrii H.    schedule 25.06.2019

Я думаю, вас может заинтересовать метод chunk в Query Builder.

Разделение результатов

Если вам нужно работать с тысячами записей базы данных, рассмотрите возможность использования метода фрагментов. Этот метод извлекает небольшой фрагмент результатов за раз и передает каждый фрагмент в замыкание для обработки. Этот метод очень удобен для написания Artisan-команд, обрабатывающих тысячи записей. Например, давайте работать со всей таблицей пользователей частями по 100 записей за раз:

$response = new \Symfony\Component\HttpFoundation\StreamedResponse(function() {
    $handle = fopen('php://output', 'w');

    DB::table('users')->orderBy('id')->chunk(100, function ($users) use($handle) {
        foreach ($users as $user) {
            fputs($handle, json_encode($user));
        }
    });

    fclose($handle);
});

return $response;

Дополнительная литература: https://laravel.com/docs/master/queries#chunking-results

Кодирование групповой передачи

Насколько мне известно, Laravel делает это по умолчанию если вы возвращаете ответ JSON.

ОБНОВИТЬ:

Мое решение было излишне запутанным и сложным. Я удалил StreamedResponse, так как в нем действительно не было необходимости. См. обновленный пример ниже.

$json_response = collect();

DB::table('users')->orderBy('id')->chunk(100, function ($users) use($json_response) {
    foreach ($users as $user) {
        $json_response->push($user);
    }
});

return $json_response->toJson();
person Linus Juhlin    schedule 12.02.2019
comment
Насчет первого абзаца: вы меня неправильно поняли. Я имел в виду ОТПРАВИТЬ данные кусками, а не ПОЛУЧИТЬ. - person Andrii H.; 12.02.2019
comment
Насчет второго абзаца: данные все равно передаются как обычно, а не кусками. Поэтому я попросил вас помочь мне создать функцию для преобразования модели Eloquent в фрагментированный результат. - person Andrii H.; 12.02.2019
comment
Если вы хотите ОТПРАВИТЬ данные, то я лично настроил бы конечную точку для пользователя, где вы используете метод чанка в построителе запросов — независимо от того, настроили ли вы это в своей красноречивой модели или сделали это в контроллере, это ваш выбор — и вы будете быть в состоянии chunk сделать его доступным для клиента. Я действительно верю, что то, что вы ищете, - это метод, который я продемонстрировал в своем ответе. Чтобы лучше понять ваше затруднительное положение, может быть, вы можете сказать мне - если это так, - почему вы не можете использовать вышеуказанный метод. - person Linus Juhlin; 12.02.2019
comment
Я не могу понять смысл первого метода. Цикл, хотя для того, чтобы сделать что? Ничего... Этот метод используется только для фрагментации моделей Eloquent, а не ответа API. Механизм CTE делает следующее (как я понял): он преобразует данные в байт-код, но предварительно он преобразует каждую строку в комбинацию разрывов строк, длины данных и фактических данных. Звучит сложно (Википедия объясняет это лучше). Но верхний метод просто разбивает записи базы данных на части. - person Andrii H.; 12.02.2019
comment
@Nod Я добавил новый пример, надеюсь, это поможет вам. Возможно, вам понадобятся пользовательские заголовки, чтобы указать, что это ответ JSON, но в остальном все должно быть в порядке. :) - person Linus Juhlin; 12.02.2019
comment
К сожалению, это не сработает. Вот причины: в последнем примере вы просто отправляете записи в коллекцию и возвращаете коллекцию в виде строки JSON. Это никак не изменит поведение. Лично я возвращаю результат с помощью response()->json(), поэтому нет необходимости преобразовывать массив в json и передавать его в ответ (избыточные шаги). - person Andrii H.; 12.02.2019