在JavaScript中编写数百万行csv的最佳方法

时间:2019-02-15 14:31:35

标签: javascript node.js csv

我有一个庞大的数组,大约有1000万个对象,每个对象都有11个不同的键和值对。

将数组内容写入csv的最佳方法是什么?

我尝试使用csv-writer和fast-csv-Reference

使用csv编写器

window !== 'undefined'

使用快速csv

fastcsv  
  .write(final, { headers: true })
  .pipe(ws);

这两种方法都会导致无效的字符串长度

  

.join(RECORD_DELIMITER)+ RECORD_DELIMITER;                           ^

     

RangeError:无效的字符串长度       在Array.join(本地)上

示例对象如下

csvWriter.writeRecords(final)
    .then(() => {
      console.log('...Writing csv Done. Check CSV');
    });

解决它的最佳方法是什么?任何帮助将不胜感激。谢谢。

4 个答案:

答案 0 :(得分:1)

您不能将整个数组转换为字符串,因为该字符串太长而无法处理js,而必须逐块格式化它:

const tick = () => new Promise(res => setTimeout(res, 0));

const toRow = obj =>
  obj.distance + "," +
  obj.a_id + "," + 
  obj.long + "," +
  obj.lat + "," +
  obj.DPlong + "," +
  obj.DPlat + "," +
  obj.class + "," +
  obj.way_id + "," + 
  obj.timestamp + "," + 
  obj.user + "," + 
  obj.code;

const formatChunk = array => array.map(toRow).join("\n") + "\n";

const size = 1000; // <- experiment with it
(async function() {
  for(let i = 0; i < final.length; i += size) {
    ws.write(formatChunk(final.slice(i, i + size)));
    await tick();
  }
  ws.end();
})();

答案 1 :(得分:0)

伪Java代码:

open file
for(var i = 0; i < array.length; i++){
  writeline('distance,' + array[i].distance + ... )
}
close file

答案 2 :(得分:0)

如果字符串长度有问题,那么使用csv-writer可以发出多个writeRecords调用,而不是一个。

const BATCH_SIZE = 10000;
const batchNumber = Math.ceil(final.length / BATCH_SIZE);

[...Array(batchNumber)].reduce(
    (promise, _value, i) => {
        const subArray = final.slice(BATCH_SIZE * i, BATCH_SIZE * (i+1));
        return promise.then(() => csvWriter.writeRecords(subArray));
    },
    Promise.resolve()
);

但是,如果您不需要预先构建1000万个对象阵列并通过节点流获取它们,则可以采用一种更具可扩展性的方法。

https://github.com/ryu1kn/csv-writer/issues/12#issuecomment-418666060

答案 3 :(得分:-1)

回答为时已晚,但对于需要优化的、耗时较少的解决方案的人来说 以上所有解决方案都很好,但有

  1. 时间复杂度 O(n)
  2. 高存储复杂度 O(n) 或高内存使用问题有时应用程序可能 请求过多导致崩溃

解决方案:当用户对数据库进行 CRUD 操作时,例如在放置请求中,维护一个同步的 CSV 文件

app.put('/product/:id', (res,req)=>{
    // step 1 do update operation in db
    // step 2 do update operation in CSV file

    return res.send('OK 200')

})

这样下次当用户请求 CSV 用户可以立即获取 CSV 文件

快乐编码:)