Не знаю, как использовать csv-writer для записи файла CSV строка за строкой после вызова API - PullRequest
1 голос
/ 03 июня 2019

Мой пример использования следующий.У меня есть приложение node.js, которое выполняет вызовы API, подавляемые внешней библиотекой limiter.Затем я выполняю вызовы API со скоростью 27 вызовов в секунду, пока не закончу цикл по всему массиву, который содержит один параметр, который мне нужно передать в API.Получив ответ от API, я хочу сохранить эти данные в файле CSV.

Моя идея состоит в том, чтобы писать файл CSV построчно, как только я получу результат от API.Я использую csv-writer для этого.

Согласно документации

"Вы можете продолжать запись записей в один и тот же файл, вызывая writeRecords несколько раз (но необходимодождитесь выполнения обещания предыдущего вызова writeRecords). "

Promise.resolve() .then(() => csvWriter.writeRecords(records1)) .then(() => csvWriter.writeRecords(records2))

Я также думал о том, чтобы попытаться заставить код дождаться завершения и запроса APICSV-файл, который будет написан тогда, однако, я не знаю, как это сделать.Я не смог найти в Интернете ни одного примера о чем-то подобном.Все они, кажется, начинаются с объекта / массива.Я также попытался добавить уловку для любых исключений, даже если это не рекомендуется в документации.Что-то вроде этих строк.

          Promise.resolve()
    .then(() => csvWriter.writeRecords(outp))
    .catch(err => console.log(err))

Это мой код:

var RateLimiter = require('limiter').RateLimiter;
const createCsvWriter = require('csv-writer').createArrayCsvWriter;  

 var limiter = new RateLimiter(27, 'second', true);

let final = [xxxxxxxx, xxxxxxx, ..... ]

const csvWriter = createCsvWriter({
    header: ['NAME'],
    path: 'out.csv'
});

let outp = []
final.forEach((item, index) => {

//limit the API calls according to the limiter defined above
  limiter.removeTokens(1, () => {


    ExternalAPIcall({ number: item}, (error, response) => {
       if (error) {
         console.error(error)
       } else {
         console.log(response.status_message)

        output.push(response.status_message)]

         const records = output.map(NAME => [NAME])
              csvWriter.writeRecords(records)



       }
     })


   })
 })

Я ожидал бы, что файл будет записываться построчно, и тогда я мог бы использовать append: trueпереписать файл, если необходимо, как указано в документации.Однако эта ошибка выдается.

(узел: 3540) UnhandledPromiseRejectionWarning: необработанное отклонение обещания.Эта ошибка возникла либо из-за того, что внутри асинхронной функции возникла ошибка без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch ().(идентификатор отклонения: 86) (узел: 3540) UnhandledPromiseRejectionWarning: TypeError: Невозможно прочитать свойство 'map' undefined в ArrayCsvStringifier.getCsvLine (/ Users / xxxx / Desktop / nodexcel / node_modules / csv-writer / dist / lib / csv-stringifiers/abstract.js:19:14) в Array.from.record (/Users/xxxx/Desktop/nodexcel/node_modules/csv-writer/dist/lib/csv-stringifiers/abstract.js:14:61) в функции.из (нативного) в ArrayCsvStringifier.stringifyRecords (/Users/xxxxx/Desktop/nodexcel/node_modules/csv-writer/dist/lib/csv-stringifiers/abstract.js:14:32) в CsvWriter.(/Users/xxxx/Desktop/nodexcel/node_modules/csv-writer/dist/lib/csv-writer.js:24:55) в Generator.next () в / Users / xxxx / Desktop / nodexcel / node_modules / csv-writer / dist / lib / csv-writer.js: 7: 71 в новом Promise () в __aaiter (/Users/xxxxx/Desktop/nodexcel/node_modules/csv-writer/dist/lib/csv-writer.js:3:12) at CsvWriter.writeRecords (/Users/xxx/Desktop/nodexcel/node_modules/csv-writer/dist/lib/csv-writer.js:22:16) (узел: 3540) UnhandledPromiseRejectionWarning: необработанное отклонение обещания.Эта ошибка возникла либо из-за того, что внутри асинхронной функции возникла ошибка без блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch ().(id отклонения: 88)

Спасибо за ваше время.

С уважением, J.


решено: проблема в том, что writeRecords ожидает> как Array> иЯ проходил мимо массива.https://github.com/ryu1kn/csv-writer/blob/86a57cae5d68f91d738318aff1de3b6d55d6b718/README.md#csvwriterwriterecordsrecords, Этот бит решил эту проблему.

const records = llenar.map (NAME => [NAME]) csvWriter.writeRecords (records)

Я обновил код выше

Ответы [ 3 ]

0 голосов
/ 03 июня 2019

Если вы хотите, чтобы ваш файл записывался построчно, тогда вам нужно дождаться этих обещаний, Promise.all вам не поможет.

Однако вы можете заставить посылы выполняться последовательно, используя метод .reduce.

Вы можете попробовать код ниже:

var RateLimiter = require('limiter').RateLimiter;
var createCsvWriter = require('csv-writer').createArrayCsvWriter;
var limiter = new RateLimiter(27, 'second', true);

const csvWriter = createCsvWriter({
  header: ['NAME'],
  path: './out.csv'
});

/** Mocked module - you can delete this */
const nexmo = {
  numberInsight: {
    get: (item, cb) => {
      if (typeof cb !== 'function') {
        cb = () => {}
      }
      let msg = {
        status: 1,
        status_message: `${item.number} - have passed`
      };
      cb(null, msg);
    }
  }
}

var final = ['john', 'mike', 'elise', 'valentine']

final = final.reduce((accumulator, item, index) => {

  return accumulator.then(() => {

    return new Promise(resolve => {

      limiter.removeTokens(1, (err, remainingReq) => {

        if (err) {
          resolve(Promise.resolve(err.message));
        } else {

          nexmo.numberInsight.get({
            level: 'basic',
            number: item
          }, (error, response) => {

            if (error) {
              resolve(Promise.resolve(error.message));
            } else {

              csvWriter.writeRecords([
                [response.status_message]
              ]).then(() => {
                resolve(response.status_message)
              }).catch(writerErr => {
                resolve(writerErr.message);
              })

            }

          })

        }

      })

    })

  })
}, Promise.resolve());

final.then(lastPromiseResponse => {

  console.log('final', lastPromiseResponse)

}).catch(err => {
  console.log('final err', err);
})
0 голосов
/ 22 июня 2019

Ни обновленный фрагмент кода в вопросном сообщении Хавилондо, ни ответ darklightcode, похоже, не ждут выполнения обещания, возвращаемого writeRecords, прежде чем вызывать следующий вызов writeRecords. Это может привести к потере данных, если основной поток не может записать в файл достаточно быстро.

Мы можем написать что-то вроде ниже, чтобы убедиться, что writeRecords вызывается после завершения предыдущего вызова. Поскольку я использовал util.promisify, требуется Node.js v8 +. (Если вы используете более низкую версию Node, просто напишите ее самостоятельно.)

const {RateLimiter} = require('limiter');
const createCsvWriter = require('csv-writer').createArrayCsvWriter;
const {promisify} = require('util');

const limiter = new RateLimiter(27, 'second');

const csvWriter = createCsvWriter({
    header: ['NAME'],
    path: 'out.csv'
});

const removeTokens = promisify(limiter.removeTokens.bind(limiter));
const callExternalApi = promisify(ExternalAPIcall);

final.reduce(async (promise, item) => {
    await promise;
    await removeTokens(1);

    const {status_message} = await callExternalApi({number: item});
    const records = [[status_message]];
    await csvWriter.writeRecords(records);
}, Promise.resolve()).catch(e => {
    console.error(e.stack);
});

Я запустил этот фрагмент с определениями ExternalAPIcall и final следующим образом:

const ExternalAPIcall = (params, callback) => {
    setTimeout(() => {
        callback(null, {status_message: `success: ${params.number}`});
    }, 0);
};

const final = [1, 2, 3, 4, 5, 6, 7, 8, 9];
0 голосов
/ 03 июня 2019

Используйте следующую ссылку на код.Здесь я взял ключи от объекта JSON для примера.

   let someObject = yourArray[0] // JSON array
   let csvHeader = [] 
   for(let key in someObject) {
     csvHeader.push({ id: key, title: key });
   }
    const csvWriter = createCsvWriter({
        path: csvFilePath,
        header: csvHeader
    });
    return await csvWriter.writeRecords(yourArray);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...