Search code examples
javascriptnode.jsazureazure-blob-storageexceljs

Uploading output of ExcelJS to Azure Blob Storage in NodeJS


So I am using ExcelJS to create an Excel file. Currently I am saving the file to disk. The data I am adding to the file is coming in from an API call.

let options = {
  filename: 'pathtofile',
  useStyles: true,
  useSharedStrings: true
}

let workbook = new Excel.stream.xlsx.WorkbookWriter(options)
let sheet = workbook.addWorksheet('myWorksheet')

// add some data to the file

sheet.commit()
workbook.commit()

I would like to now change it so it uploads to Azure Blob Storage. ExcelJS allows the specification of a stream instead of a filename in which to commit to. So I've decided to use Memory Streams JS so now the options look like this.

let stream = new streams.WritableStream()

let options = {
  stream: stream,
  useStyles: true,
  useSharedStrings: true
}

From reading the Azure documentation, the two most suitable methods seems to be createBlockBlobFromStream() and createWriteStreamToBlockBlob() and they both appear to want a Readable Stream (correct me if I'm wrong). This is where I'm stuck as I have a Writable Stream from using ExcelJS but I need a Readable Stream for Azure Blob Storage. Obviously I can still write the file to disk; create a Readable Stream from the file; and then finally delete the file after uploading to Azure Blob Storage but that is a lot of overhead. Am I going about this in a really roundabout way?


Solution

  • There is a explain at the section Streaming XLSX Writer

    If neither stream nor filename is specified in the options, the workbook writer will create a StreamBuf object that will store the contents of the XLSX workbook in memory. This StreamBuf object, which can be accessed via the property workbook.stream, can be used to either access the bytes directly by stream.read() or to pipe the contents to another stream.

    So you can try the following code snippet, without setting a filename in options:

    let blobSvc = azure.createBlobService();
    
    let options = {
      useStyles: true,
      useSharedStrings: true
    }
    
    let workbook = new Excel.stream.xlsx.WorkbookWriter(options)
    let sheet = workbook.addWorksheet('myWorksheet')
    sheet.columns = [
        { header: 'Id', key: 'id', width: 10 },
        { header: 'Name', key: 'name', width: 32 },
        { header: 'D.O.B.', key: 'DOB', width: 10, outlineLevel: 1 }
    ];
    sheet.commit()
    workbook.commit()
    workbook.stream.pipe(blobSvc.createWriteStreamToBlockBlob('mycontainer','test.xlsx',function(err,result){
        if(err)console.log(err)
        console.log(result);
    }))