Search code examples
node.jsmulter

multer. How can I skip a file if it is on disk?


How can I skip a file using multer upload if it is already on disk? It re-downloads and updates when I use the following code

attachments.component.js

import React, { Component } from 'react';
import axios from 'axios';

export default class FilesUploadComponent extends Component {

    constructor(props) {
        super(props);

        this.onFileChange = this.onFileChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);

        this.state = {
            imgCollection: ''
        }
    }

    onFileChange(e) {
        this.setState({ imgCollection: e.target.files })
    }

    onSubmit(e) {
        e.preventDefault()

        let formData = new FormData();
        for (const key of Object.keys(this.state.imgCollection)) {
            formData.append('imgCollection', this.state.imgCollection[key])
        }
        axios.post("/api/attachments/upload", formData, {
        }).then(() => {}).catch(() => {})
    }

    render() {
        return (
            <div className="container">
                <div className="row">
                    <form onSubmit={this.onSubmit}>
                        <div className="form-group">
                            <input type="text" name="FIO" />
                        </div>
                        <div className="form-group">
                            <input type="file" name="imgCollection" onChange={this.onFileChange} multiple />
                        </div>
                        <div className="form-group">
                            <button className="btn btn-primary" type="submit">Upload</button>
                        </div>
                    </form>
                </div>
            </div>
        )
    }
}

attachments.router.js

let express = require('express'),
    multer = require('multer'),
    router = express.Router(),
    Attachment = require('../models/Attachment');

const DIR = './public/';

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, DIR);
    },
    filename: (req, file, cb) => {
        const fileName = file.originalname;
        cb(null, fileName)
    }
});

const upload = multer({
    storage: storage
});



router.post('/upload', upload.array('imgCollection'), async (req, res) => {
    try{
        const reqFiles = [];
        for (let i = 0; i < req.files.length; i++) {
            const file_name = 'public/' +req.files[i].filename
            reqFiles.push(file_name)
            const find = await Attachment.findOne({ file_name: file_name })
            if(find){
                return res.status(400).json( { message: 'File ' + file_name + ' already save' } )
            }
        }
        console.log(reqFiles)
        reqFiles.map(async name => {
            const attachment = new Attachment({
                file_name: name
            })
            await attachment.save()
        })
        res.status(201).json({ message: 'Files saved' })
    }catch (e) {
        console.log(e.message)
    }
})

module.exports = router;

Attachment.model.js

const {Schema, model} = require('mongoose')

const schema = new Schema({
    file_name: {
        type: String, required: true, unique: true
    }
},
{
    timestamps: true
})

module.exports = model('Attachment', schema)

Ideally, I would like to first perform some operations in mongodb, then give the correct answer to the user, but to get the necessary data, I first save the files using multer. Tell me what I'm doing wrong


Solution

  • Make use of the fileFilter function. Here's a full example:

    const express = require('express')
    const multer = require('multer')
    const fs = require('fs')
    const path = require('path')
    
    const app = express()
    const port = 3000
    
    const UPLOAD_DIR = '/tmp/'
    
    const fileFilter = (req, file, cb) => {
        if (fs.existsSync(path.join(UPLOAD_DIR, file.originalname))) {
            console.log('skipped')
            cb(null, false)
            return
        }
    
        cb(null, true)
    }
    
    const storage = multer.diskStorage({
        destination: function (req, file, cb) {
            cb(null, UPLOAD_DIR)
        },
        filename: function (req, file, cb) {
            const fileName = file.originalname;
            cb(null, fileName)
        }
    })
    
    const upload = multer({
        fileFilter,
        storage,
    });
    
    app.post('/', upload.single('avatar'), (req, res) => {
        res.send('Uploaded!')
    })
    
    app.listen(port, () => {
        console.log(`Example app listening at http://localhost:${port}`)
    })