Добрый день. Мне интересно, могу ли я использовать фрагментированное кодирование передачи (далее CTE) в ответе API? У меня большие данные в базе и мне нужно передать их клиенту одним запросом. Я много читал о механизме CTE, но не нашел, как это реализовать, к сожалению.
Одна важная вещь, которую следует упомянуть: отсутствие пагинации. Предполагается, что это автономная система, которая возвращает данные обратно на конечную точку клиента, а не на веб-страницу.
Как я уже говорил, данные хранятся в базе данных. Единственная проблема заключается в том, как разделить данные на сегменты (фрагменты) и отправить их в одном ответе API (один за другим).
Спасибо.
Например, он может содержать 10 записей, но у каждой есть поле json с более чем 100 000 записей.
Таким образом, было бы идеально передавать каждую запись одну за другой как кусок.






Я думаю, вас может заинтересовать метод chunk в Query Builder.
Chunking Results
If you need to work with thousands of database records, consider using the chunk method. This method retrieves a small chunk of the results at a time and feeds each chunk into a Closure for processing. This method is very useful for writing Artisan commands that process thousands of records. For example, let's work with the entire users table in chunks of 100 records at a time:
$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();
Насчет первого абзаца: вы меня неправильно поняли. Я имел в виду ОТПРАВИТЬ данные кусками, а не ПОЛУЧИТЬ.
По поводу второго абзаца: данные все равно передаются как обычно, а не кусками. Поэтому я попросил вас помочь мне создать функцию для преобразования модели Eloquent в фрагментированный результат.
Если вы хотите ОТПРАВИТЬ данные, то я лично настроил бы конечную точку для пользователя, где вы используете метод чанка в построителе запросов — независимо от того, настроили ли вы это в своей красноречивой модели или сделали это в контроллере, это ваш выбор — и вы будете быть в состоянии chunk вниз, чтобы клиент мог управлять им. Я действительно верю, что то, что вы ищете, - это метод, который я продемонстрировал в своем ответе. Чтобы лучше понять ваше затруднительное положение, может быть, вы можете сказать мне - если это так, - почему вы не можете использовать вышеуказанный метод.
Я не могу понять смысл первого метода. Цикл, хотя для того, чтобы сделать что? Ничего... Этот метод используется только для фрагментации моделей Eloquent, а не ответа API. Механизм CTE делает следующее (как я понял): он преобразует данные в байт-код, но предварительно он преобразует каждую строку в комбинацию разрывов строк, длины данных и фактических данных. Звучит сложно (Википедия объясняет это лучше). Но верхний метод просто разбивает записи базы данных на части.
@Nod Я добавил новый пример, надеюсь, это поможет вам. Возможно, вам понадобятся пользовательские заголовки, чтобы указать, что это ответ JSON, но в остальном все должно быть в порядке. :)
К сожалению, это не сработает. Вот причины: в последнем примере вы просто отправляете записи в коллекцию и возвращаете коллекцию в виде строки JSON. Это никак не изменит поведение. Лично я возвращаю результат с помощью response()->json(), поэтому нет необходимости преобразовывать массив в json и передавать его в ответ (избыточные шаги).
В моем конкретном случае я решил свою проблему, используя этот код (пример):
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();
Я не совсем понимаю, какое отношение к проблеме имеет кодирование передачи по частям. Что вы подразумеваете под «разбить данные на сегменты»? С какими проблемами вы столкнулись, просто отправив весь набор результатов обратно? О каком именно количестве записей идет речь?