Как создать большой JSON файл и вывести его в качестве response в Node.JS?

У меня есть довольно простой контроллер, который срабатывает при обращении к определенному URL адресу. Как видите, контроллер забирает значения параметров (start_date и end_date), которые были указаны в URL и использует их в запросе к базе данных MySQL. Другими словами, моя задача получить пул данных за определенное период и в качестве ответа прислать JSON.

async function get_all_information(req, res, next) {
    try {
        let start_date = req.query.start_date;
        let end_date = req.query.end_date;

        const binds = {};
        binds.start_date = start_date;
        binds.end_date = end_date;

        let query = `SOME LONG SQL STATEMENT`;

        await pool.query(query, binds, function (error, results) {
            if (error) throw error;

            console.log(results); // ~ 10 seconds

            res.send(JSON.stringify(results)); // ~ 15 seconds
        });
    } catch (error) {
        next(error);
    }
}


За месяц запрос обрабатывается порядка 10 секунд и возвращает большой пул данных. Если быть точнее sql запрос возвращает 227011 строк. Весь этот результат я пытался преобразовать в JSON формат с помощью метода stringify(). Приложение Postman, который я использовал для тестирования просто вещается и программа останавливается. При обращении к URL адресу в браузере данные приходят частями и грузятся очень долго. В терминале вижу следующее:

GET /api/information?start_date =2018-09-01%2000:00:00&end_date=2018-09-30%2023:59:59 200 15490.389 ms - 144219608


Я попытался проанализировать и заметил, что пул данных за день создает ~ 13 МБ JSON файл. Можно предположить, что пул данных за месяц создаст плюс минус ~ 400 МБ JSON файл.

Как обычно в Node.JS вы создаете большие JSON файлы? Какой Best Practice? Что обычно делают, когда нужно вернуть большой объем данных?
  • Вопрос задан
  • 1853 просмотра
Пригласить эксперта
Ответы на вопрос 3
miraage
@miraage
Старый прогер
Просто стримьте респонс. Если уж вообще нагрузки - тогда по крону создавайте файлы, но отдавайте всё равно через стрим, чтобы экономить нагрузку на оперативку на сервере.

https://www.npmjs.com/package/mysql#streaming-quer...
https://medium.freecodecamp.org/node-js-streams-ev...

// EDIT

https://www.npmjs.com/package/mysql#piping-results...

Само собой, надо будет еще посидеть пошаманить. Пример на коленке набросан)

async function getExpensiveDataFromDb(req, res) {
   // запускаем запрос без второго параметра
  connection.query('YOUR HUGE SQL QUERY')
    // получаем из него стрим
    // из документации пример, что в буффер по 5 записей за раз пихаем 
    .stream({ highWaterMark: 5 })
    // перенаправляем его в res
    // который является class Http.Response extends Stream (Writable)
    .pipe(res);
}
Ответ написан
2ord
@2ord
Варианты:
  1. Возвращать данные, разбив на части (допустим, 100+100+100+37 строк). API должен предоставлять возможность получения данных порциями.
  2. Загружать данные в какое-то облачное хранилище и оповещать о готовности отчета
  3. Возвращать просто аггрегированные данные
  4. Если речь о синхронизации БД, то настроить репликацию или же способом №1
Ответ написан
Комментировать
@4uTePoK
Данные зависят от входных параметров, поэтому смысла особо в статику переводить нет.
Решение, конечно, зависит от проблемы, которую вы пытаетесь решить.
Из того, что понятно из вашего запроса. Ответ:
Лучше данные батчить примерно по 100 элементов и в лупе стримить результаты.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы