Search code examples
node.jsfirebasefirebase-storagebusboy

Uploads multiples images with multiples files field


I'm having hard time for the last few day on how to upload multiples images on firebase with busboy. I want to use 3 fields with 3 different images. so I can store it in one folder. I also want the image to have the field name

I found one topic that helped me use Promise.all and forEach but it didn't worked out for me

  • storing all files in an array
    var Promise = require('promise');
    const Busboy = require("busboy");
    const fs = require("fs");
    const os = require("os");
    const path = require("path");


    const busboy = new Busboy({ headers: req.headers });
    let imageToAdd = {};
    let imagesToUpload = []
    let newFileName;

    busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
        const imageExtension =  filename.split('.')[filename.split('.').length - 1];
        filename = `${fieldname}.${imageExtension} `
        newFileName = filename
        const filepath = path.join(os.tmpdir(), filename);
        imageToAdd = { file: filepath, type: mimetype };
        file.pipe(fs.createWriteStream(filepath));
        imagesToUpload = [...imagesToUpload, imageToAdd]
    });
  • loop over the files array and store the promises in a new array
  • then wait all the promise to resolve with Promise.all
    busboy.on("finish", () => {
        let promises = []
        imagesToUpload.forEach((imageToBeUploaded) => {
            promises.push(
                admin
                .storage()
                .bucket(`${config.storageBucket}`)
                .upload(imageToBeUploaded.file, {
                    resumable: false,
                    destination: `projectname/${newFileName}`,
                    metadata: {
                        metadata: {
                          contentType: imageToBeUploaded.type,
                        }
                    }
                })          
            )     

        }) 
        Promise.all(promises)
        .then(res => { 
            res.status(200).json({msg: 'Successfully uploaded all images')
        })
        .catch(err => {
            res.status(500).json({error: err.code})
        })
    })
    busboy.end(req.rawBody);
})

Only the last image is stored in my firebase storage.

Is someone can help me with this ?

thanks


Solution

  • You only have one newFileName in your code, while you have an array of imagesToUpload. So you're uploading each of those images to the same newFileName and end up with whichever of the uploads completes last.

    You'll want to keep an array of newFileNames, to match up with the array of imagesToUpload.

    Something like:

    const busboy = new Busboy({ headers: req.headers });
    let imageToAdd = {};
    let imagesToUpload = []
    let newFileNames = [];
    
    busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
        const imageExtension =  filename.split('.')[filename.split('.').length - 1];
        filename = `${fieldname}.${imageExtension} `
        const filepath = path.join(os.tmpdir(), filename);
        imageToAdd = { file: filepath, type: mimetype };
        file.pipe(fs.createWriteStream(filepath));
    
        imagesToUpload.push(imageToAdd);
        newFileNames.push(filename);
    });
    
    ...
    
    busboy.on("finish", () => {
        let promises = imagesToUpload.map((imageToBeUploaded, index) => {
            admin
            .storage()
            .bucket(`${config.storageBucket}`)
            .upload(imageToBeUploaded.file, {
                resumable: false,
                destination: `projectname/${newFileNames[index]}`,
                metadata: {
                    metadata: {
                      contentType: imageToBeUploaded.type,
                    }
                }
            })          
        }) 
        Promise.all(promises)
          ...