Search code examples
javascriptnode.jsfilenestjsmulter

How do I read an uploaded file (text/.csv) using nestjs and Multer


I need to read my CSV file in the controller to add CSV file data into my DB. But I don't know the way to that. I search for an answer so many times but I can't find an answer to related my question. I really need your help with this. Thank you.

My Controller method :-

  @Post()
  @UseInterceptors(FileInterceptor('filename', { dest: './uploads' }))
  async upload(@UploadedFile() files: Express.Multer.File) {
    console.log(files);
  }

My console log output:-

enter image description here


Solution

  • I have just finished with an exactly similar scenario. First I uploaded csv file to my uploads/csv directory with the name 'data.csv'

    I am using this library for parsing data into JSON

    https://www.npmjs.com/package/nest-csv-parser

    Here is core to my controller file.

    @Post('upload')
      @UseInterceptors(FileInterceptor('file', {
        storage: diskStorage({
          destination: './uploads/csv',
          filename: csvFileName,
        }),
        fileFilter: csvFileFilter,
      }))
      uploadFile(@UploadedFile() file: Express.Multer.File) {
        const response = {
          message: "File uploaded successfully!",
          data: { 
            originalname: file.originalname,
            filename: file.filename,
          }
        };
        return response;
      }

    Here is a code for my component app.module.ts

    import { Module } from '@nestjs/common';
    import { TypeOrmModule } from '@nestjs/typeorm';
    import { Coin } from './coin.entity';
    import { CoinsController } from './coins.controller';
    import { CoinsService } from './coins.service';
    import {CsvModule} from "nest-csv-parser";
    import {MulterModule} from "@nestjs/platform-express";
    
    @Module({
      imports: [
        TypeOrmModule.forFeature([Coin]),
          CsvModule,
        MulterModule.register({
          dest: './uploads/csv',
        }),
      ],
      controllers: [
        CoinsController,
      ],
      providers: [CoinsService]
    })
    export class CoinsModule { }

    I've also created on utils or a helper file where I am having all csv created logic

    import {extname, join} from 'path';
    
    export const csvFileFilter = (req, file, callback) => {
        if (!file.originalname.match(/\.(csv)$/)) {
            return callback(new Error('Only CSV files are allowed!'), false);
        }
        callback(null, true);
    };
    
    export const csvFileName = (req, file, callback) => {
        //const name = file.originalname.split('.')[0];
        const fileExtName = extname(file.originalname);
        callback(null, `data${fileExtName}`);
    };
    
    export const getCSVFile = () => {
        //const name = file.originalname.split('.')[0];
        const filePath = join(__dirname, "..", "..", "uploads/csv", "data.csv");
        return filePath;
    };
    
    export const editFileName = (req, file, callback) => {
        const name = file.originalname.split('.')[0];
        const fileExtName = extname(file.originalname);
        const randomName = Array(4)
            .fill(null)
            .map(() => Math.round(Math.random() * 16).toString(16))
            .join('');
        callback(null, `${name}-${randomName}${fileExtName}`);
    };

    And finally, I have a different route to import or parse data, and then I could save it into my database.

    // You have to define entity that is as 2nd argument of csvParsing and also a mendatory.
    class Coin {
      unix: number
      date: string
      symbol: string
      open: number
      close: number
      high: number
      low: number
      "Volume BTC": number
      "Volume USDT": number
      tradecount: number
    }
    
    
    // An import end route
    @Get('import')
      async import(){
        const csvPath = getCSVFile();
        console.log(" => ", csvPath);
        const stream = fs.createReadStream(csvPath)
        const entities: Coin[] = await this.csvParser.parse(stream, Coin)
        // You will get JSON
        console.log(entities);
      }

    You can do it in the same controller action /upload. Although, in my scenario, I have to do it through a different API call.