Josh Brown
Josh Brown

Reputation: 43

ExpressJS JSON to CSV

I have this ExpressJS code that I am working with. My application sends an array of _id's which I search for and grab from mongo. I am then trying to generate a CSV of the data returned. The code below is working as expected. It is writing the CSV to the root directory of my application. The modification I am wanting to make is that I want the file to download to the users machine. I have been googling this topic for quite some time now and everyone says that in order to download a file you need to use fs.createWriteStream or res.download() however I dont know how to implement it with my current method structure. Obviously it needs to happen inside json2csv() after the csv is created. Id rather not have to write the file, stream, then delete. Id like it if I could just stream.

The json2csv package I am using is here: https://www.npmjs.com/package/json2csv

router.post('/Equipment/Report', function(req, res, next) {
    var filteredData = req.body;
    console.log(filteredData);
    Equipment.find({_id: { $in: filteredData }}, function(err, Equipment) {
        console.log(Equipment);
        var fields = ['ClassPrefix', 'UnitNumber'];
        json2csv({ data: Equipment, fields: fields}, function(err, csv) {
            if (err) console.log(err);
            fs.writeFile('file.csv', csv, function(err) {
                if (err) throw err;
                console.log('file saved');
            });
        });
    });
    //console.log(filteredData);
});

EDIT to suggested code -

router.post('/Equipment/Report', function(req, res, next) {
    var filteredData = req.body;
    console.log(filteredData);
    Equipment.find({_id: { $in: filteredData }}, function(err, Equipment) {
        console.log(Equipment);
        var fields = ['ClassPrefix', 'UnitNumber'];
        json2csv({ data: Equipment, fields: fields}, function(err, csv) {
            if (err) console.log(err);
            console.log(csv);
            res.attachment('data.csv');
            res.send(csv);
        });
    });
});

This does not download any file. Logs a response of 200.

Upvotes: 4

Views: 4725

Answers (4)

eyoeldefare
eyoeldefare

Reputation: 2303

That is something you can do on the client side. You should send the data to the client and make the browser download the csv file on client browser.

//Inside your server router
json2csv({ data: Equipment, fields: fields}, function(err, csv) {
  if (err) {
    next(err);
  }
      res.setHeader('Content-disposition', 'attachment; filename=data.csv');
      res.set('Content-Type', 'text/csv');
      res.send(csv);
});

On the client side, make the browser download it.

window.open(requestedUrl);

Upvotes: 0

user2879704
user2879704

Reputation:

I think, you want to download the csv file on the browser and so, you need not create a file on the server side.

You need to set the response content type correctly, for browser to treat it as a downloadable link.

json2csv({ data: Equipment, fields: fields}, function(err, csvStr) {
  if (err) {
    console.log(err);
    res.statusCode = 500;
    return res.end(err.message);
  }
  res.header("Content-Disposition",attachment;filename=data.csv"); 
  res.type("text/csv");
  res.send(200, csvStr);
})

Upvotes: 2

mscdex
mscdex

Reputation: 106726

There is no need to write the string to a file on disk first, just use res.attachment() and then write the csv string to the response:

router.post('/Equipment/Report', function(req, res, next) {
  var filteredData = req.body;
  Equipment.find({_id: { $in: filteredData }}, function(err, Equipment) {
    if (err) {
      console.log(err);
      res.statusCode = 500;
      return res.end(err.message);
    }
    var fields = ['ClassPrefix', 'UnitNumber'];
    json2csv({ data: Equipment, fields: fields}, function(err, csv) {
      if (err) {
        console.log(err);
        res.statusCode = 500;
        return res.end(err.message);
      }
      res.attachment('data.csv');
      res.end(csv);
    });
  });
});

Upvotes: 2

Julián Duque
Julián Duque

Reputation: 9727

You can use the following code snippet instead of the writeFile

res.attachment('file.csv');
res.send(csv)

Upvotes: 3

Related Questions