Node js excel import

The Excel file is a spreadsheet file format created by Microsoft for use with Microsoft Excel. You can use the file to create, view, edit, analyse data, charts, budgets and more. In this tutorial, I will show you how to upload/import Excel file data into MySQL Database using Node.js & read-excel-file.

Related Posts:
– Upload/store images in MySQL using Node.js, Express & Multer
– How to upload/store images in MongoDB using Node.js, Express & Multer
– Import CSV data into MySQL using Node.js
– Import CSV data into PostgreSQL using Node.js
– Import CSV file into MongoDB collection using Node.js

CSV file instead:
Node.js: Upload CSV file data into Database with Express

Contents

  • Node.js Rest APIs for uploading Excel Files
  • Node.js Rest API returns Excel File
  • Technology
  • Project Structure
  • Setup Node.js Excel File Upload project
  • Configure MySQL database & Sequelize
  • Initialize Sequelize
  • Define the Sequelize Model
  • Create middleware for uploading & storing Excel file
  • Create Controller for uploading/importing Excel file
  • Define Routes for uploading Excel File
  • Create Express app server
  • Run & Check
  • Conclusion
  • Further Reading
  • Source Code

Node.js Rest APIs for uploading Excel Files

Assume that we have an .xlsx file that contains Tutorial data in Tutorials sheet as following:

node-js-upload-import-excel-file-database-exceljs-file

We’re gonna create a Node.js Application that provides APIs for:

  • uploading Excel File to the Node.js Express Server & storing data in MySQL Database
  • getting list of items from MySQL table
  • downloading MySQL table data as Excel file

After the Excel file is uploaded successfully, tutorials table in MySQL database will look like this:

node-js-upload-import-excel-file-database-exceljs-table

If we get list of Tutorials, the Node.js Rest Apis will return:

node-js-upload-import-excel-file-database-exceljs-retrieve-data

Node.js Rest API returns Excel File

If you send request to /api/excel/download, the server will return a response with an Excel file tutorials.xlsx that contains data in MySQL table:

node-js-upload-import-excel-file-database-exceljs-download-file

How to do this?
You need to set the HTTP header:

"Content-disposition" : "attachment; filename=[yourFileName]" 
"Content-Type" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

You can find step by step for downloading Excel file in the tutorial:
Node.js Download Excel file example with exceljs

These are APIs to be exported:

Methods Urls Actions
POST /api/excel/upload upload an Excel File
GET /api/excel/tutorials get List of items in db table
GET /api/excel/download download db data as Excel file

Technology

  • express 4.17.1
  • multer 1.4.2
  • mysql2 2.1.0
  • read-excel-file 4.0.6
  • sequelize 5.21.13

Project Structure

This is the project directory that we’re gonna build:

node-js-upload-import-excel-file-database-exceljs-project-structure

db.config.js exports configuring parameters for MySQL connection & Sequelize.
models/index.js: uses configuration above to initialize Sequelize, models/tutorial.model.js for Sequelize Tutorial data model.
middleware/upload.js: initializes Multer Storage engine and defines middleware function to save Excel file in uploads folder.
excel.controllers.js:

  • use read-excel-file to read Excel file in uploads folder, then save data to MySQL database with Sequelize Model.
  • export functions for retrieving all tutorials in database table

routes/tutorial.routes.js: defines routes for endpoints that is called from HTTP Client, use controllers (along with middleware) to handle requests.
server.js: initializes routes, runs Express app.

Setup Node.js Excel File Upload project

Open command prompt, change current directory to the root folder of our project.
Install Express, Multer, Sequelize, Mysql2 with the following command:

npm install express multer sequelize mysql2 read-excel-file

The package.json file will look like this:

{
  "name": "node-js-upload-download-excel-files",
  "version": "1.0.0",
  "description": "Node.js Upload/Import Excel files to MySQL Database and download Excel File",
  "main": "src/server.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [
    "node js",
    "upload",
    "import",
    "download",
    "excel",
    "files",
    "mysql",
    "database"
  ],
  "author": "bezkoder",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "multer": "^1.4.2",
    "mysql2": "^2.1.0",
    "read-excel-file": "^4.0.6",
    "sequelize": "^5.21.13"
  }
}

Configure MySQL database & Sequelize

In the src folder, we create a separate config folder for configuration with db.config.js file like this:

module.exports = {
  HOST: "localhost",
  USER: "root",
  PASSWORD: "123456",
  DB: "testdb",
  dialect: "mysql",
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  }
};

First five parameters are for MySQL connection.
pool is optional, it will be used for Sequelize connection pool configuration:

  • max: maximum number of connection in pool
  • min: minimum number of connection in pool
  • idle: maximum time, in milliseconds, that a connection can be idle before being released
  • acquire: maximum time, in milliseconds, that pool will try to get connection before throwing error

For more details, please visit API Reference for the Sequelize constructor.

Initialize Sequelize

Now we initialize Sequelize in src/models folder.

Create src/models/index.js with the following code:

const dbConfig = require("../config/db.config.js");

const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
  host: dbConfig.HOST,
  dialect: dbConfig.dialect,
  operatorsAliases: false,

  pool: {
    max: dbConfig.pool.max,
    min: dbConfig.pool.min,
    acquire: dbConfig.pool.acquire,
    idle: dbConfig.pool.idle
  }
});

const db = {};

db.Sequelize = Sequelize;
db.sequelize = sequelize;

db.tutorials = require("./tutorial.model.js")(sequelize, Sequelize);

module.exports = db;

We’re gonna define Tutorial model in the next step.

Define the Sequelize Model

In models folder, create tutorial.model.js file like this:

module.exports = (sequelize, Sequelize) => {
  const Tutorial = sequelize.define("tutorial", {
    title: {
      type: Sequelize.STRING
    },
    description: {
      type: Sequelize.STRING
    },
    published: {
      type: Sequelize.BOOLEAN
    }
  });

  return Tutorial;
};

This Sequelize Model represents tutorials table in MySQL database. These columns will be generated automatically: id, title, description, published, createdAt, updatedAt.

After initializing Sequelize, we don’t need to write CRUD functions, Sequelize supports all of them:

  • create a new Tutorial: create(object)
  • create multiple Tutorials: bulkCreate(objects)
  • find a Tutorial by id: findByPk(id)
  • get all Tutorials: findAll()
  • update, remove Tutorials…

We’re gonna use bulkCreate() and findAll() in our Controller.

Create middleware for uploading & storing Excel file

Inside middleware folder, create upload.js file with the following code:

const multer = require("multer");

const excelFilter = (req, file, cb) => {
  if (
    file.mimetype.includes("excel") ||
    file.mimetype.includes("spreadsheetml")
  ) {
    cb(null, true);
  } else {
    cb("Please upload only excel file.", false);
  }
};

var storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, __basedir + "/resources/static/assets/uploads/");
  },
  filename: (req, file, cb) => {
    console.log(file.originalname);
    cb(null, `${Date.now()}-bezkoder-${file.originalname}`);
  },
});

var uploadFile = multer({ storage: storage, fileFilter: excelFilter });
module.exports = uploadFile;

In the code above, we’ve done these steps:
– First, we import multer module.
– Next, we configure multer to use Disk Storage engine.
– We also define a filter to only allow file with excel format.

You can see that we have two options here:
destination determines folder to store the uploaded files.
filename determines the name of the file inside the destination folder.
– We add the [timestamp]-bezkoder- prefix to the file’s original name to make sure that the duplicates never occur.

Create Controller for uploading/importing Excel file

controllers/tutorial/excel.controller.js

const db = require("../../models");
const Tutorial = db.tutorials;

const readXlsxFile = require("read-excel-file/node");

const upload = async (req, res) => {
  try {
    if (req.file == undefined) {
      return res.status(400).send("Please upload an excel file!");
    }

    let path =
      __basedir + "/resources/static/assets/uploads/" + req.file.filename;

    readXlsxFile(path).then((rows) => {
      // skip header
      rows.shift();

      let tutorials = [];

      rows.forEach((row) => {
        let tutorial = {
          id: row[0],
          title: row[1],
          description: row[2],
          published: row[3],
        };

        tutorials.push(tutorial);
      });

      Tutorial.bulkCreate(tutorials)
        .then(() => {
          res.status(200).send({
            message: "Uploaded the file successfully: " + req.file.originalname,
          });
        })
        .catch((error) => {
          res.status(500).send({
            message: "Fail to import data into database!",
            error: error.message,
          });
        });
    });
  } catch (error) {
    console.log(error);
    res.status(500).send({
      message: "Could not upload the file: " + req.file.originalname,
    });
  }
};

const getTutorials = (req, res) => {
  Tutorial.findAll()
    .then((data) => {
      res.send(data);
    })
    .catch((err) => {
      res.status(500).send({
        message:
          err.message || "Some error occurred while retrieving tutorials.",
      });
    });
};

module.exports = {
  upload,
  getTutorials,
};

Now look at the upload function:
– First we get and check file upload from req.file.
– Next we use read-excel-file to read Excel file in uploads folder, the data which is returned as rows will be changed to tutorials array.
– Then we use Sequelize model bulkCreate() method to save the tutorials array (id, title, description, published) to MySQL database.

The getTutorials() function uses findAll() method to return all Tutorials stored in the database tutorials table.

Define Routes for uploading Excel File

When a client sends request for an endpoint using HTTP request (POST Excel file, GET tutorials), we need to determine how the server will response by setting up the routes.

These are our routes:

  • /api/excel/upload: POST
  • /api/excel/tutorials: GET

Create a tutorial.routes.js inside routes folder with content like this:

const express = require("express");
const router = express.Router();
const excelController = require("../controllers/tutorials/excel.controller");
const upload = require("../middlewares/upload");

let routes = (app) => {
  router.post("/upload", upload.single("file"), excelController.upload);
  router.get("/tutorials", excelController.getTutorials);

  app.use("/api/excel", router);
};

module.exports = routes;

You can see that we use a controller from excel.controller.js.

Create Express app server

Finally, we create an Express server.

server.js

const express = require("express");
const app = express();
const db = require("./models");
const initRoutes = require("./routes/tutorial.routes");

global.__basedir = __dirname + "/..";

app.use(express.urlencoded({ extended: true }));
initRoutes(app);

db.sequelize.sync();
// db.sequelize.sync({ force: true }).then(() => {
//   console.log("Drop and re-sync db.");
// });

let port = 8080;
app.listen(port, () => {
  console.log(`Running at localhost:${port}`);
});

In the code above, we initialize Express Router and call Sequelize sync() method.

db.sequelize.sync();

In development, you may need to drop existing tables and re-sync database. Just use force: true as following code:


db.sequelize.sync({ force: true }).then(() => {
  console.log("Drop and re-sync db.");
});

Run & Check

First we need to create uploads folder with the path resources/static/assets.
On the project root folder, run this command: node src/server.js

Let’s use Postman to make HTTP POST request with an Excel file.

node-js-upload-import-excel-file-database-exceljs-upload

The result in MySQL tutorials table:

node-js-upload-import-excel-file-database-exceljs-table

Conclusion

Today we’ve built a Rest CRUD API using Node.js Express to upload and import data from Excel file to Mysql database table.

We also see how to use read-excel-file to read data from Excel file, Sequelize to retrieve items in database table without need of boilerplate code.

If you want to add Pagination while getting data from MySQL table, you can find the instruction at:
Server side Pagination in Node.js with Sequelize & MySQL

For downloading Excel file:
Node.js Download Excel file example with exceljs

Or working with CSV file instead:
Node.js: Upload CSV file data into Database with Express

Happy learning! See you again.

Further Reading

  • https://www.npmjs.com/package/express
  • https://www.npmjs.com/package/multer
  • https://sequelize.org/v3/api/model/
  • read-excel-file

– Node.js Rest APIs with Express & MySQL
– Node.js Rest APIs with Express & MySQL (including Sequelize)

Fullstack:
– Vue.js + Node.js + Express + MySQL example
– Vue.js + Node.js + Express + MongoDB example
– Angular 8 + Node.js Express + MySQL example
– Angular 10 + Node.js Express + MySQL example
– Angular 11 + Node.js Express + MySQL example
– Angular 12 + Node.js Express + MySQL example
– React + Node.js + Express + MySQL example

Security: Node.js – JWT Authentication & Authorization example
Deployment:
– Deploying/Hosting Node.js app on Heroku with MySQL database
– Dockerize Node.js Express and MySQL example – Docker Compose

Node.js & MySQL Associations:
– One-to-Many Relationship example
– Many-to-Many Relationship example

Source Code

You can find the complete source code for this example on Github.

In this article, we gonna learn how to import and export excel and csv in node.js. 

1. Let’s create a new express project using express generator.

npm i -g express-generator
express node-excel-csv --view=hbs

2. Create a folder config and inside this create a file database.js.

config/database.js

module.exports = { 
    host: process.env.DB_HOST,
    database: process.env.DB_DATABASE,
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD
}

3. Install dotenv npm package.

npm i dotenv

After Installation import dotenv in app.js

require('dotenv').config();

4. Create a .env file in the root and add these environment variables.

DB_HOST=localhost            // your database host
DB_DATABASE=node-excel-csv  // your database name
DB_USERNAME=root           // your database username 
DB_PASSWORD=              // your database password

5. Install sequelize and mysql2 npm packages.

npm i sequelize mysql2

6. Create a models folder and inside this create a connection.js and movie.model.js

models/connection.js

const { Sequelize } = require('sequelize');
const config = require('../config/database'); 

const sequelize = new Sequelize(config.database, config.username, config.password, {
    host: config.host,
    dialect: 'mysql',
    operatorsAliases: 'false',
    logging: false
});  

module.exports = sequelize

models/movie.model.js

const { DataTypes } = require('sequelize');
const sequelize = require('./connection');

const Movie = sequelize.define('Movie', {
    movie: {
        type: DataTypes.STRING 
    },
    category: {
        type: DataTypes.STRING 
    },
    director: {
        type: DataTypes.STRING 
    },
    rating: {
        type: DataTypes.FLOAT(8, 1) 
    }
}, {
    underscored: true
}); 
module.exports = Movie;

Note:- Don’t forget to create a movies table. https://github.com/ultimateakash/node-excel-csv/blob/master/node-excel-csv.sql

Above Schema Based on the import(excel or csv) file.

7. Install multer and uniqid npm packages.

npm i multer, uniqid

8. create a folder helpers and inside this folder create a file uploader.js

const multer = require('multer');
const uniqid = require('uniqid'); 
const path = require('path');

const storage = multer.diskStorage({
    destination: function(req, file, cb) {
        cb(null, 'storage/uploads/')
    },
    filename: function(req, file, cb) {
        cb(null, Date.now() + uniqid() + path.extname(file.originalname))
    }
})
const upload = multer({ storage: storage });

exports.upload = (field) => upload.single(field); 

9. Create a storage folder and inside this create uploads and outputs folder.

10. Install xlsx npm package.

npm i xlsx

xlsx package provides a bunch of functions for reading and writing CSV/Excel files.

Parsing functions:-

      XLSX.read(data, read_opts) attempts to parse data

      XLSX.readFile(filename, read_opts) attempts to read filename and parse.

Note:- you can pass raw option to false  if you want formatted data.(example — formatted date)

XLSX.read(data, { raw: false })
XLSX.readFile(filename, { raw: false })

Writing functions:-

      XLSX.write(wb, write_opts) attempts to write the workbook

      XLSX.writeFile(wb, filename, write_opts) attempts to write workbook

Utility Functions:-

      Constructing:-

            book_new creates an empty workbook

            book_append_sheet adds a worksheet to a workbook

       Importing:

           aoa_to_sheet converts an array of arrays of JS data to a worksheet

           json_to_sheet converts an array of JS objects to a worksheet

          sheet_add_aoa adds an array of arrays of JS data to an existing worksheet.

          sheet_add_json adds an array of JS objects to an existing worksheet.

    Exporting:

          sheet_to_json converts a worksheet object to an array of JSON objects.

          sheet_to_csv generates delimiter-separated-values output.

Ref:- https://www.npmjs.com/package/xlsx

11. Create a folder controllers and inside this folder create movie.controller.js

controllers/movie.controller.js

const XLSX = require("xlsx"); 
const Movie = require("../models/movie.model")
const outputPath = 'storage/outputs' 

exports.index = async (req, res) => { 
    const movies = await Movie.findAll();
    return res.render('index', { movies });
}

exports.import = async (req, res) => { 
    const wb = XLSX.readFile(req.file.path); 
    const sheets = wb.SheetNames;
    
    if(sheets.length > 0) {
        const data = XLSX.utils.sheet_to_json(wb.Sheets[sheets[0]]);
        const movies = data.map(row => ({
            movie: row['Movie'],
            category: row['Category'],
            director: row['Director'],
            rating: row['Rating']
        }))
        await Movie.bulkCreate(movies); 
    }
    return res.redirect('/');
}

exports.export = async (req, res) => {
    const movies = await Movie.findAll({
        attributes: [
            'id', 
            'movie', 
            'category', 
            'director', 
            'rating'
        ],
        raw: true
    }); 

    const headings = [
        ['Id', 'Movie', 'Category', 'Director', 'Rating']
    ]; 

    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.json_to_sheet(movies, { 
        origin: 'A2', 
        skipHeader: true 
    });
    XLSX.utils.sheet_add_aoa(ws, headings); 
    XLSX.utils.book_append_sheet(wb, ws, 'Movies');

    const buffer = XLSX.write(wb, { bookType: 'csv', type: 'buffer' }); 
    res.attachment('movies.csv');

    return res.send(buffer);
}

Note:- In this article, I am using import file headers if your file doesn’t have a headers row then you can use indexes.

You need to pass header option with sheet_to_json

const data = XLSX.utils.sheet_to_json(wb.Sheets[sheets[0]], { header: 1 });
const movies = data.map(row => ({
    movie: row[0],
    category: row[1],
    director: row[2],
    rating: row[3]
}))

In the above code you can change the extension based on the file you want to import or export. (.xlsx, .xls, .csv)

Note:- If want to store your exported file on the server you can use writeFile function.

const wb = XLSX.utils.book_new();
const ws = XLSX.utils.json_to_sheet(movies, { 
    origin: 'A2', 
    skipHeader: true 
});
XLSX.utils.sheet_add_aoa(ws, headings); 
XLSX.utils.book_append_sheet(wb, ws, 'Movies');

const filepath = `${outputPath}/movies.csv`;
XLSX.writeFile(wb, filepath); 

return res.download(filepath)

12. Create routes.

routes/index.js

const express = require('express');
const router = express.Router();
const movieController = require('../controllers/movie.controller');
const { upload } = require('../helpers/uploader');

router.get('/',                        movieController.index);
router.post('/import', upload('file'), movieController.import);
router.get('/export',                  movieController.export);

module.exports = router;

13. Open views/index.hbs and add the following code.

<main>
    <div class="row mb-2">
        <div class="col-sm-8 offset-2">
            <div class="row">
                <div class="col-md-6">
                    <form method="POST" action="/import" enctype="multipart/form-data"> 
                        <div class="input-group">
                            <div class="custom-file">
                                <input type="file" name="file" class="custom-file-input" id="inputGroupFile" required accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel">
                                <label class="custom-file-label" for="inputGroupFile">Choose file</label>
                            </div>
                            <div class="input-group-append">
                                <button type="submit" class="btn btn-primary float-right mr-2">Import <i class="fa fa-upload"></i></button>
                            </div>
                        </div>
                    </form>
                </div>
                <div class="col-md-6">
                    <a href="/export" class="btn btn-primary float-right {{#unless movies.length}} disabled {{/unless }}" role="button" aria-disabled="true">
                        Export <i class="fa fa-download"></i>
                    </a>
                </div>
            </div>
        </div>
    </div>
    <div class="row">
        <div class="col-sm-8 offset-2">
            <table class="table">
                <thead>
                    <tr>
                        <th scope="col">Id</th>
                        <th scope="col">Movie</th>
                        <th scope="col">Category</th>
                        <th scope="col">Director</th>
                        <th scope="col">Rating</th>
                    </tr>
                </thead>
                <tbody>
                    {{#each movies}} 
                        <tr>
                            <th scope="row">{{ this.id }}</th>
                            <td>{{ this.movie }}</td>
                            <td>{{ this.category }}</td>
                            <td>{{ this.director }}</td>
                            <td><span class="badge bg-warning text-dark">{{ this.rating }}</span></td>
                        </tr>
                    {{else}}
                        <tr>
                            <td colspan="5" class="text-center">No Movies Found.</td>
                        </tr>
                    {{/each}}  
                </tbody>
            </table>
        </div>
    </div>
</main>

Note:- please checkout github repo — https://github.com/ultimateakash/node-excel-csv

14. Finally start the project.

npm start

Open http://localhost:3000 and try import and export.

Extras:- if you want to read a file without uploading then you can use multer.memoryStorage()

const multer = require('multer'); 
const upload = multer({ storage: multer.memoryStorage() });
exports.upload = (field) => upload.single(field);

with memoryStorage() you can access the file buffer.

const wb = XLSX.read(req.file.buffer); 
const sheets = wb.SheetNames;

Sample Excel CSV Files:- https://github.com/ultimateakash/node-excel-csv/tree/master/sample%20files

Checkout my full node-excel-csv example. https://github.com/ultimateakash/node-excel-csv

If you facing any issues. don’t hesitate to comment below. I will be happy to help you.

Thanks.

Node.js is an open-source and cross-platform JavaScript runtime environment that can also be used to read from a file and write to a file which can be in txt, ods, xlsx, docx, etc format.

The following example covers how an excel file(.xlsx) file is read from an excel file and then converted into JSON and also to write to it. It can be achieved using a package called xlsx to achieve our goal.

Module Installation: You can install xlsx module using the following command:

npm install xlsx

Note: For the following example, text.xlsx is a dummy data file that has been used.

Filename: test.xlsx 

Sheet 1:

Sheet 2:

So the excel file test.xlsx has 2 sheets, one having Student details and another having lecturer details.

Read Operation Filename: read.js 

Javascript

const reader = require('xlsx')

const file = reader.readFile('./test.xlsx')

let data = []

const sheets = file.SheetNames

for(let i = 0; i < sheets.length; i++)

{

   const temp = reader.utils.sheet_to_json(

        file.Sheets[file.SheetNames[i]])

   temp.forEach((res) => {

      data.push(res)

   })

}

console.log(data)

Explanation: First, the npm module is included in the read.js file and then the excel file is read into a workbook i.e constant file in the above program.

The number of files in that particular excel file is available in the SheetNames property of the workbook. It can be accessed as follows:

const sheets = file.SheetNames  // Here the value of the sheets will be 2

A for loop is run until the end of the excel file starting from the first page. One of the most important functions used in the code above is the sheet_to_json() function present in the utils module of the xlsx package. It accepts a worksheet object as a parameter and returns an array of JSON objects.

There is a forEach loop which iterates through every JSON object present in the array temp and pushes it into a variable data which would contain all the data in JSON format.

Finally, the data is printed or any other modification can be performed on the array of JSON objects.

Step to run the application:

Run the read.js file using the following command:

node read.js

Output:

Write Operation In the following example, we will convert an array of JSON objects into an excel sheet and append it to the file.

Filename: write.js

Javascript

const reader = require('xlsx')

const file = reader.readFile('./test.xlsx')

let student_data = [{

    Student:'Nikhil',

    Age:22,

    Branch:'ISE',

    Marks: 70

},

{

    Student:'Amitha',

    Age:21,

    Branch:'EC',

    Marks:80

}]

const ws = reader.utils.json_to_sheet(student_data)

reader.utils.book_append_sheet(file,ws,"Sheet3")

reader.writeFile(file,'./test.xlsx')

Explanation: Here we have an array of JSON objects called student_data. We use two main functions in this program i.e json_to_sheet() which accepts an array of objects and converts them into a worksheet and another function is the book_append_sheet() to append the worksheet into the workbook.

Finally, all the changes are written to the test.xlsx file using writeFile() function which takes a workbook and a excel file as input parameter.

Step to run the application:

Run the read.js file using the following command:

node write.js

Output: The final test.xlsx file would look something like this: 

Sheet 1:

Sheet 2:

Sheet 3: We can see sheet 3 is appended into the test.xlsx as shown below:

There may be times when you need to generate an Excel file from your Node.js application. You may need to get data from a database or a web service, then output it to an Excel file for further reporting or analysis. SpreadJS makes this possible without any Excel requirements on the server.

Node.js is a popular event-driven JavaScript runtime that is typically used in creating network applications. It can handle multiple connections simultaneously and doesn’t depend on threads like most other models.

In this tutorial, learn how to use SpreadJS to gather information entered by the user and automatically export it to an Excel file—all in your Node.js application.

  1. Get Started with SpreadJS and Node.js
  2. Use the SpreadJS npm Package
  3. Read an Excel File In Your Node.js Application
  4. Gather User Input
  5. Fill Out Your Excel File
  6. Export Node.js Out to Excel

With the power of SpreadJS, performance is not affected whether using SpreadJS by itself or with Node.js.

Download the sample zip for this project.

Ready to get Started? Download SpreadJS Today!

Import/Export XLSX Node.js

Get Started with SpreadJS Spreadsheets and Node.js

To start, we’ll need to install Node.js and the Mock-Browser, BufferJS, and FileReader, each of which can be found at these links:

Installing Node.js via Package Manager

Mock-Browser

BufferJS

FileReader

While you can use most IDE to create this application, we’ll use Visual Studio 2019 in this blog. Once Visual Studio is open, create a new application using Create a new project, and then search for «Blank Node.js Console Application«. Please give it a name and specify a location to create the project.

This will automatically create the required files and open up the “app.js” file, which is the only file we’ll be changing.

To install the packages in the project, right-click the «npm» header in the Solution Explorer, click Install New npm Packages and search and install each package for «Mock-Browser», «BufferJS», and «FileReader».

Once you have that installed, the dependencies should update in the package.json file:

{
  "name": "spread-jsnode-js",
  "version": "0.0.1",
  "description": "SpreadJSNodeJS",
  "main": "app.js",
  "author": {
    "name": ""
  },
  "dependencies": {
    "@grapecity/spread-excelio": "^16.0.4",
    "@grapecity/spread-sheets": "^16.0.4",
    "bufferjs": "^3.0.1",   
    "filereader": "^0.10.3",
    "mock-browser": "^0.92.14"
  }
}

In this sample, we’ll use the File System Module of Node.js. We can load that in:

var fs = require('fs');

To use SpreadJS with Node.js, we can load the Mock-Browser that we installed:

var mockBrowser = require('mock-browser').mocks.MockBrowser;

Before loading the SpreadJS script, we’ll need to initialize the mock-browser. Initialize the variables that we may need to use later in the application, particularly the «window» variable:

global.window = mockBrowser.createWindow();
global.document = window.document;
global.navigator = window.navigator;
global.HTMLCollection = window.HTMLCollection;
global.getComputedStyle = window.getComputedStyle;

Initialize the FileReader library:

var fileReader = require('filereader');
global.FileReader = fileReader;

Use the SpreadJS npm Package

The SpreadJS and ExcelIO packages will need to be added to the project. You can add these to your project by right-clicking the «npm» section of the Solution Explorer and selecting Install New npm Packages. You should be able to search for «GrapeCity» and install the following two packages:

@grapecity/spread-sheets

@grapectiy/spread-excelio

Once the SpreadJS npm packages have been added to the project, the package.json should be automatically uploaded with the correct dependencies:

{
  "name": "spread-jsnode-js",
  "version": "0.0.1",
  "description": "SpreadJSNodeJS",
  "main": "app.js",
  "author": {
    "name": ""
  },
  "dependencies": {
    "@grapecity/spread-excelio": "^16.0.4",
    "@grapecity/spread-sheets": "^16.0.4",
    "bufferjs": "^3.0.1",
    "filereader": "^0.10.3",
    "mock-browser": "^0.92.14"
  }
}

Now we’ll need to require that in the app.js file:

var GC = require('@grapecity/spread-sheets');
var SJSExcel = require('@grapecity/spread-excelio');

When using the npm package, the license key also needs to be set for both:

GC.Spread.Sheets.LicenseKey = "<YOUR KEY HERE>";
SJSExcel.LicenseKey = "<YOUR KEY HERE>";

In this particular application, we’ll show the user which version of SpreadJS they are using. To do this, we can require the package.json file and then reference the dependency to get the version number:

var packageJson = require('./package.json');
console.log('n** Using SpreadJS Version "' + packageJson.dependencies["@grapecity/spread-sheets"] + '" **');

Read the Excel File Into Your Node.js Application

We’ll read in an existing Excel template file, getting data from the user. Next, place the data into the file and export it. In this case, the file is an invoice that the user can edit.

Start by initializing the workbook and Excel IO variables, as well as the variables for the sheet index:

var wb = new GC.Spread.Sheets.Workbook();

var billingInvoiceSheetIndex = 1;
var companySetupSheetIndex = 2;

var excelIO = new SJSExcel.IO();

Let’s wrap our code in a try/catch block as we read in the file. Then we can initialize the variable “readline” – which is essentially a library that allows you to read data that the user inputs into the console. Next, we’ll store it into a JavaScript array that we can use to fill out the Excel file easily:

// Instantiate the spreadsheet and modify it
console.log('nManipulating Spreadsheetn---');
try {
    var file = fs.readFileSync('./content/billingInvoiceTemplate.xlsx');
    excelIO.open(file.buffer, (data) => {
        wb.fromJSON(data);
        const readline = require('readline');

        var invoice = {
            generalInfo: [],
            invoiceItems: [],
            companyDetails: []
        };
    });
} catch (e) {
    console.error("** Error manipulating spreadsheet **");
    console.error(e);
}

Gather User Input

Import/Export Excel Node.js

The above image shows the Excel file we are using. The first information we want to gather is the general invoice information. We can make a separate function within the excelio.open call to prompt the user in the console for each item that we’ll need.

We can create a separate array to save the data to after each input, then when we have all of the input for that section. Push it to the invoice.generalInfo array that we created:

function fillGeneralInformation() {
    console.log("-----------------------nFill in Invoice Detailsn-----------------------")
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });
    var generalInfoArray = [];
    rl.question('Invoice Number: ', (answer) => {
        generalInfoArray.push(answer);
        rl.question('Invoice Date (dd Month Year): ', (answer) => {
            generalInfoArray.push(answer);
            rl.question('Payment Due Date (dd Month Year): ', (answer) => {
                generalInfoArray.push(answer);
                rl.question('Customer Name: ', (answer) => {
                    generalInfoArray.push(answer);
                    rl.question('Customer Company Name: ', (answer) => {
                        generalInfoArray.push(answer);
                        rl.question('Customer Street Address: ', (answer) => {
                            generalInfoArray.push(answer);
                            rl.question('Customer City, State, Zip (<City>, <State Abbr> <Zip>): ', (answer) => {
                                generalInfoArray.push(answer);
                                rl.question('Invoice Company Name: ', (answer) => {
                                    generalInfoArray.push(answer);
                                    rl.question('Invoice Street Address: ', (answer) => {
                                        generalInfoArray.push(answer);
                                        rl.question('Invoice City, State, Zip (<City>, <State Abbr> <Zip>): ', (answer) => {
                                            generalInfoArray.push(answer);
                                            rl.close();

                                            invoice.generalInfo.push({
                                                "invoiceNumber": generalInfoArray[0],
                                                "invoiceDate": generalInfoArray[1],
                                                "paymentDueDate": generalInfoArray[2],
                                                "customerName": generalInfoArray[3],
                                                "customerCompanyName": generalInfoArray[4],
                                                "customerStreetAddress": generalInfoArray[5],
                                                "customerCityStateZip": generalInfoArray[6],
                                                "invoiceCompanyName": generalInfoArray[7],
                                                "invoiceStreetAddress": generalInfoArray[8],
                                                "invoiceCityStateZip": generalInfoArray[9],
                                            });
                                            console.log("General Invoice Information Stored");
                                            fillCompanyDetails();
                                        });
                                    });
                                });
                            });
                        });
                    });
                });
            });
        });
    });
}

Within that function, we call «fillCompanyDetails,» we’ll gather information about the company to fill into the second sheet of the workbook. The function will be very similar to the previous function:

function fillCompanyDetails() {
    console.log("-----------------------nFill in Company Detailsn-----------------------");
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    var companyDetailsArray = []
    rl.question('Your Name: ', (answer) => {
        companyDetailsArray.push(answer);
        rl.question('Company Name: ', (answer) => {
            companyDetailsArray.push(answer);
            rl.question('Address Line 1: ', (answer) => {
                companyDetailsArray.push(answer);
                rl.question('Address Line 2: ', (answer) => {
                    companyDetailsArray.push(answer);
                    rl.question('Address Line 3: ', (answer) => {
                        companyDetailsArray.push(answer);
                        rl.question('Address Line 4: ', (answer) => {
                            companyDetailsArray.push(answer);
                            rl.question('Address Line 5: ', (answer) => {
                                companyDetailsArray.push(answer);
                                rl.question('Phone: ', (answer) => {
                                    companyDetailsArray.push(answer);
                                    rl.question('Facsimile: ', (answer) => {
                                        companyDetailsArray.push(answer);
                                        rl.question('Website: ', (answer) => {
                                            companyDetailsArray.push(answer);
                                            rl.question('Email: ', (answer) => {
                                                companyDetailsArray.push(answer);
                                                rl.question('Currency Abbreviation: ', (answer) => {
                                                    companyDetailsArray.push(answer);
                                                    rl.question('Beneficiary: ', (answer) => {
                                                        companyDetailsArray.push(answer);
                                                        rl.question('Bank: ', (answer) => {
                                                            companyDetailsArray.push(answer);
                                                            rl.question('Bank Address: ', (answer) => {
                                                                companyDetailsArray.push(answer);
                                                                rl.question('Account Number: ', (answer) => {
                                                                    companyDetailsArray.push(answer);
                                                                    rl.question('Routing Number: ', (answer) => {
                                                                        companyDetailsArray.push(answer);
                                                                        rl.question('Make Checks Payable To: ', (answer) => {
                                                                            companyDetailsArray.push(answer); rl.close();
                                                                            invoice.companyDetails.push({ "yourName": companyDetailsArray[0], "companyName": companyDetailsArray[1], "addressLine1": companyDetailsArray[2], "addressLine2": companyDetailsArray[3], "addressLine3": companyDetailsArray[4], "addressLine4": companyDetailsArray[5], "addressLine5": companyDetailsArray[6], "phone": companyDetailsArray[7], "facsimile": companyDetailsArray[8], "website": companyDetailsArray[9], "email": companyDetailsArray[10], "currencyAbbreviation": companyDetailsArray[11], "beneficiary": companyDetailsArray[12], "bank": companyDetailsArray[13], "bankAddress": companyDetailsArray[14], "accountNumber": companyDetailsArray[15], "routingNumber": companyDetailsArray[16], "payableTo": companyDetailsArray[17] });
                                                                            console.log("Invoice Company Information Stored");
                                                                            console.log("-----------------------nFill in Invoice Itemsn-----------------------");
                                                                            fillInvoiceItemsInformation();
                                                                        });
                                                                    });
                                                                });
                                                            });
                                                        });
                                                    });
                                                });
                                            });
                                        });
                                    });
                                });
                            });
                        });
                    });
                });
            });
        });
    });
}

Now that we have the basic information for the invoice, we can focus on gathering the individual invoice items, which we’ll do in another function called «fillInvoiceItemsInformation.» Before each item, we’ll ask the user if they would like to add an item. If they keep entering «y», then we’ll gather that item’s information, then ask again until they type «n»:

function fillInvoiceItemsInformation() {
    const rl = readline.createInterface({
        input: process.stdin, output: process.stdout
    });
    var invoiceItemArray = [];
    rl.question('Add item?(y/n): ', (answer) => {
        switch (answer) {
            case "y": console.log("-----------------------nEnter Item Informationn-----------------------");
                rl.question('Quantity: ', (answer) => {
                    invoiceItemArray.push(answer);
                    rl.question('Details: ', (answer) => {
                        invoiceItemArray.push(answer);
                        rl.question('Unit Price: ', (answer) => {
                            invoiceItemArray.push(answer);
                            invoice.invoiceItems.push({
                                "quantity": invoiceItemArray[0], "details": invoiceItemArray[1], "unitPrice": invoiceItemArray[2]
                            });
                            console.log("Item Information Added");
                            rl.close();
                            fillInvoiceItemsInformation();
                        });
                    });
                });
                break;
            case "n": rl.close();
                return fillExcelFile();
                break;
            default: console.log("Incorrect option, Please enter 'y' or 'n'.");
        }
    });
}

Add Data to the Excel Spreadsheet

After gathering all the required invoice information, we can fill out the Excel file. For the billing information and company setup, we can manually set each value in the cell from the JavaScript array:

function fillExcelFile() {
    console.log("-----------------------nFilling in Excel filen-----------------------");
    fillBillingInfo();
    fillCompanySetup();
}

function fillBillingInfo() {
    var sheet = wb.getSheet(billingInvoiceSheetIndex);
    sheet.getCell(0, 2).value(invoice.generalInfo[0].invoiceNumber);
    sheet.getCell(1, 1).value(invoice.generalInfo[0].invoiceDate);
    sheet.getCell(2, 2).value(invoice.generalInfo[0].paymentDueDate);
    sheet.getCell(3, 1).value(invoice.generalInfo[0].customerName);
    sheet.getCell(4, 1).value(invoice.generalInfo[0].customerCompanyName);
    sheet.getCell(5, 1).value(invoice.generalInfo[0].customerStreetAddress);
    sheet.getCell(6, 1).value(invoice.generalInfo[0].customerCityStateZip);
    sheet.getCell(3, 3).value(invoice.generalInfo[0].invoiceCompanyName);
    sheet.getCell(4, 3).value(invoice.generalInfo[0].invoiceStreetAddress);
    sheet.getCell(5, 3).value(invoice.generalInfo[0].invoiceCityStateZip);
}

function fillCompanySetup() {
    var sheet = wb.getSheet(companySetupSheetIndex);
    sheet.getCell(2, 2).value(invoice.companyDetails[0].yourName);
    sheet.getCell(3, 2).value(invoice.companyDetails[0].companyName);
    sheet.getCell(4, 2).value(invoice.companyDetails[0].addressLine1);
    sheet.getCell(5, 2).value(invoice.companyDetails[0].addressLine2);
    sheet.getCell(6, 2).value(invoice.companyDetails[0].addressLine3);
    sheet.getCell(7, 2).value(invoice.companyDetails[0].addressLine4);
    sheet.getCell(8, 2).value(invoice.companyDetails[0].addressLine5);
    sheet.getCell(9, 2).value(invoice.companyDetails[0].phone);
    sheet.getCell(10, 2).value(invoice.companyDetails[0].facsimile);
    sheet.getCell(11, 2).value(invoice.companyDetails[0].website);
    sheet.getCell(12, 2).value(invoice.companyDetails[0].email);
    sheet.getCell(13, 2).value(invoice.companyDetails[0].currencyAbbreviation);
    sheet.getCell(14, 2).value(invoice.companyDetails[0].beneficiary);
    sheet.getCell(15, 2).value(invoice.companyDetails[0].bank);
    sheet.getCell(16, 2).value(invoice.companyDetails[0].bankAddress);
    sheet.getCell(17, 2).value(invoice.companyDetails[0].accountNumber);
    sheet.getCell(18, 2).value(invoice.companyDetails[0].routingNumber);
    sheet.getCell(19, 2).value(invoice.companyDetails[0].payableTo);
}

The template we are using has a specific number of rows laid out for the items in the invoice. The user may add more than the max. In this case, we can simply add more rows to the sheet. We’ll add the rows before setting the items in the sheet from the array:

function fillInvoiceItems() {
    var sheet = wb.getSheet(billingInvoiceSheetIndex);
    var rowsToAdd = 0;
    if (invoice.invoiceItems.length > 15) {
        rowsToAdd = invoice.invoiceItems.length - 15;
        sheet.addRows(22, rowsToAdd);
    }
    var rowIndex = 8;
    if (invoice.invoiceItems.length >= 1) {
        for (var i = 0; i < invoice.invoiceItems.length; i++) {
            sheet.getCell(rowIndex, 1).value(invoice.invoiceItems[i].quantity);
            sheet.getCell(rowIndex, 2).value(invoice.invoiceItems[i].details);
            sheet.getCell(rowIndex, 3).value(invoice.invoiceItems[i].unitPrice);
            rowIndex++;
        }
    }
}

Export Node.js Out to an Excel XLSX Spreadsheet

After the information has been filled out in the workbook, we can export the workbook to an Excel file. To do this, we’ll use the excelio open function. In this case, just put the date in the filename:

function exportExcelFile() {
    excelIO.save(wb.toJSON(), (data) => {
        fs.appendFileSync('Invoice' + new Date().valueOf() + '.xlsx', new Buffer(data), function (err) {
            console.log(err);
        });
        console.log("Export success");
    }, (err) => {
        console.log(err);
    }, { useArrayBuffer: true });
}

You can export your workbook to an Excel file with the above code snippet. Your completed file will look like this:

Import/Export Excel Node.js

Utilizing SpreadJS in conjunction with Node.js demonstrates another example of the versatility and extensibility of SpreadJS! Check out our blog page for more articles like this, demos, videos, and tutorials.

If you have any questions, feedback, or demo requests, please comment below!

Ready to get Started? Download SpreadJS Today!

node-xlsx

npm version

npm total downloads

npm monthly downloads

npm license

github main workflow

Features

Straightforward excel file parser and builder.

  • Relies on SheetJS xlsx module to parse/build excel sheets.
  • Built with TypeScript for static type checking with exported types along the
    library.

Install

npm install node-xlsx --save

Quickstart

Parse an xlsx file

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

// Parse a buffer
const workSheetsFromBuffer = xlsx.parse(fs.readFileSync(`${__dirname}/myFile.xlsx`));
// Parse a file
const workSheetsFromFile = xlsx.parse(`${__dirname}/myFile.xlsx`);

Build an xlsx file

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const data = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
var buffer = xlsx.build([{name: 'mySheetName', data: data}]); // Returns a buffer

Custom column width

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const data = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
const sheetOptions = {'!cols': [{wch: 6}, {wch: 7}, {wch: 10}, {wch: 20}]};

var buffer = xlsx.build([{name: 'mySheetName', data: data}], {sheetOptions}); // Returns a buffer

Spanning multiple rows A1:A4 in every sheets

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const data = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
const range = {s: {c: 0, r: 0}, e: {c: 0, r: 3}}; // A1:A4
const sheetOptions = {'!merges': [range]};

var buffer = xlsx.build([{name: 'mySheetName', data: data}], {sheetOptions}); // Returns a buffer

Spanning multiple rows A1:A4 in second sheet

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const dataSheet1 = [
  [1, 2, 3],
  [true, false, null, 'sheetjs'],
  ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'],
  ['baz', null, 'qux'],
];
const dataSheet2 = [
  [4, 5, 6],
  [7, 8, 9, 10],
  [11, 12, 13, 14],
  ['baz', null, 'qux'],
];
const range = {s: {c: 0, r: 0}, e: {c: 0, r: 3}}; // A1:A4
const sheetOptions = {'!merges': [range]};

var buffer = xlsx.build([
  {name: 'myFirstSheet', data: dataSheet1},
  {name: 'mySecondSheet', data: dataSheet2, options: sheetOptions},
]); // Returns a buffer

Beware that if you try to merge several times the same cell, your xlsx file will be seen as corrupted.

  • Using Primitive Object Notation Data values can also be specified in a non-abstracted representation.

Examples:

const rowAverage = [[{t: 'n', z: 10, f: '=AVERAGE(2:2)'}], [1, 2, 3]];
var buffer = xlsx.build([{name: 'Average Formula', data: rowAverage}]);

Refer to xlsx documentation for valid structure and values:

  • Format

Troubleshooting

This library requires at least node.js v10. For legacy versions, you can use this workaround before using the lib.

npm i --save object-assign
Object.prototype.assign = require('object-assign');

Contributing

Please submit all pull requests the against master branch. If your unit test contains javascript patches or features,
you should include relevant unit tests. Thanks!

Available scripts

Script Description
start Alias of test:watch
test Run mocha unit tests
test:watch Run and watch mocha unit tests
lint Run eslint static tests
compile Compile the library
compile:watch Compile and watch the library

Authors

Olivier Louvignes

  • http://olouv.com
  • http://github.com/mgcrea

Copyright and license

Apache License 2.0

Copyright (C) 2012-2014  Olivier Louvignes

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

Except where noted, this license applies to any and all software programs and associated documentation files created by the Original Author and distributed with the Software:

Inspired by SheetJS gist examples, Copyright (c) SheetJS.

Useful link

Read Excel Files and convert to JSON in Node.js

 var express = require('express'); 
    var app = express(); 
    var bodyParser = require('body-parser');
    var multer = require('multer');
    var xlstojson = require("xls-to-json-lc");
    var xlsxtojson = require("xlsx-to-json-lc");
    app.use(bodyParser.json());
    var storage = multer.diskStorage({ //multers disk storage settings
        destination: function (req, file, cb) {
            cb(null, './uploads/')
        },
        filename: function (req, file, cb) {
            var datetimestamp = Date.now();
            cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1])
        }
    });
    var upload = multer({ //multer settings
                    storage: storage,
                    fileFilter : function(req, file, callback) { //file filter
                        if (['xls', 'xlsx'].indexOf(file.originalname.split('.')[file.originalname.split('.').length-1]) === -1) {
                            return callback(new Error('Wrong extension type'));
                        }
                        callback(null, true);
                    }
                }).single('file');
    /** API path that will upload the files */
    app.post('/upload', function(req, res) {
        var exceltojson;
        upload(req,res,function(err){
            if(err){
                 res.json({error_code:1,err_desc:err});
                 return;
            }
            /** Multer gives us file info in req.file object */
            if(!req.file){
                res.json({error_code:1,err_desc:"No file passed"});
                return;
            }
            /** Check the extension of the incoming file and 
             *  use the appropriate module
             */
            if(req.file.originalname.split('.')[req.file.originalname.split('.').length-1] === 'xlsx'){
                exceltojson = xlsxtojson;
            } else {
                exceltojson = xlstojson;
            }
            try {
                exceltojson({
                    input: req.file.path,
                    output: null, //since we don't need output.json
                    lowerCaseHeaders:true
                }, function(err,result){
                    if(err) {
                        return res.json({error_code:1,err_desc:err, data: null});
                    } 
                    res.json({error_code:0,err_desc:null, data: result});
                });
            } catch (e){
                res.json({error_code:1,err_desc:"Corupted excel file"});
            }
        })
    }); 
    app.get('/',function(req,res){
        res.sendFile(__dirname + "/index.html");
    });
    app.listen('3000', function(){
        console.log('running on 3000...');
    });

Понравилась статья? Поделить с друзьями:
  • Node js create excel
  • Node js and excel
  • No word for friend in chinese
  • Node await unexpected reserved word
  • No word for factor