Node.js和Express.js创建一个大型CSV文件(1GB)并从ajax客户端下载

时间:2015-03-18 14:08:12

标签: ajax node.js csv express

UI允许用户选择几个查询参数并通过AJAX提交。 服务器将使用参数查询mongoDB,并在服务器上创建一个非常大的CSV文件(30列/ 1.5MM行/ ~1GB)。 创建文件后,服​​务器将使用URL响应AJAX调用以下载文件。 第二次调用服务器以下载CSV文件。

我的问题是扩展此解决方案...当尝试从mongoDB检索超过50,0000条记录时,Node.js内存不足。系统运行时带有4GB内存。

AJAX调用创建和下载文件:

 handleExport: function (){
        NProgress.done();
        NProgress.start();
        var data = {spMle: this.state.spMle, custMle: this.state.custMle};
        $.ajax({
            type: 'POST',
            url: '/api/aps/export',
            data: data,
            success: function (filename){
                NProgress.done();
                var url = '/api/aps/export/download/' + filename
                $('body').append("<iframe src='" + url + "' style='display: none;' ></iframe>");
                //window.open(url);
            }
        });
    },

服务器请求从MongoDB查询创建CSV文件,并发送URL以将文件下载回客户端:

var spMle       = req.body.spMle;
var custMle     = req.body.custMle;
var limit       = 50000;
var filename    = 'export.csv';
var path        = './public/downloads/' + filename;
var query       = ApsModel.find();
if (spMle !== "0"){query.where('SP_MLE_ID').equals(spMle);}
if (custMle !== "0"){query.where('Cust_MLE_ID').equals(custMle);}
if (limit){query.limit(limit);}

var writeStream = fs.createWriteStream(path);
writeStream.on('finish', function () {
    console.log('CSV file completed!');
    res.send(filename);
});
var readStream = query.stream({ transform: JSON.stringify});
var json2CsvStream = new Json2CsvStream();
json2CsvStream.on('header', function(data) {
  // console.log(' ++ yeah header found ++');
  // return console.log(data);
})
json2CsvStream.on('line', function(data) {
  console.log('row streamed');
  // return console.log(data);
});

readStream.pipe(json2CsvStream).pipe(writeStream);

下载文件的服务器请求:

router.get('/aps/export/download/:filename', function (req, res){
    var path = './public/downloads/' + req.params.filename;
    res.download(path, "export.csv")
});

1 个答案:

答案 0 :(得分:3)

使用端到端的流将其重构为以下数据流:

1)管道mongo查询 2)将数据传输到json-to-csv解析器 3)将解析后的数据传输到客户端

Jquery电话:

handleExport: function (){
        var url ="/api/aps/export/" + this.state.spMle + "/" + this.state.custMle;
        $('body').append("<iframe src='" + url + "' style='display: none;' ></iframe>");
        //window.open(url);
    },

服务器响应:

/* GET aps export */
router.get('/aps/export/:spMle/:custMle', function (req, res){
    var spMle       = req.params.spMle;
    var custMle     = req.params.custMle;
    var limit       = 250000;
    var filename    = 'export.csv';
    var query       = ApsModel.find();
    if (spMle !== "0"){query.where('SP_MLE_ID').equals(spMle);}
    if (custMle !== "0"){query.where('Cust_MLE_ID').equals(custMle);}
    if (limit){query.limit(limit);} 
    var headers = {
        'Content-Type': 'text/csv',
        'Content-disposition': 'attachment;filename=' + filename
    }
    res.writeHead(200, headers)

    var mongoStream = query.stream({transform: JSON.stringify});
    var parser = new Json2CsvStream();

    //run streams
    mongoStream.pipe(parser).pipe(res)

});