Home > Software engineering >  Uploading Multiple Files to Google Cloud Storage using For Loop
Uploading Multiple Files to Google Cloud Storage using For Loop

Time:09-17

I am trying to upload multiple files to Google Cloud Storage. I am using a for loop to for each file in the list of files which I want to upload.

However, the problem is that the for loop does not pause to wait for the upload to finish before moving on to the next upload. It eventually uploads them, however, the for loop finishes earlier which then sends back to the client the empty urlList.

How do I make it pause and wait for each upload process before moving on to the next file in the for loop?

const processFile = require('../middleware');
const { format } = require('util');
let uuidv4 = require('uuid/v4');

const Cloud = require('@google-cloud/storage');

const { Storage } = Cloud;
const storage = new Storage({
  keyFilename: './xxx.json',
  projectId: 'xxx'
});

const bucket = storage.bucket('xxx');

exports.upload = async (req, res) => {
  const urlList = [];
  await processFile(req, res); //multer

  for (var i = 0; i < req.files.length; i  ) {

    if (!req.files[i]) {
      return res.status(400).send({ message: 'Please upload a file!' });
    }

    const { originalname, buffer } = req.files[i];
    var filename = originalname
      .toLowerCase()
      .split(' ')
      .join('-');

    filename = uuidv4()   '-'   filename;

    console.log(filename);

    const blob = bucket.file(filename);

    const blobStream = blob.createWriteStream({
      resumable: false
    });

    blobStream.on('error', err => {
      res.status(500).send({ message: err.message });
    });

    blobStream.on('finish', async data => {
      const publicUrl = format(
        `https://storage.googleapis.com/${bucket.name}/${blob.name}`
      );
      urlList.push(publicUrl);

      try {
        await bucket.file(filename).makePublic();
      } catch (err) {
        console.log('failed to make it public');
        reject(err);
      }
    });

    blobStream.end(buffer);
  }

  return res.status(200).send({
    message: 'Uploaded the files successfully',
    url: urlList
  });
};

CodePudding user response:

Just put your "upload" code in a Promise that you can await in the loop. Othervise by using on the code inside of it will not follow the for loop. By using such event based code your for loop will just go trough it and can't await it to finish. This should do the trick:

const uploadFile = (f) => {
  return new Promise((resolve, reject) => {
    const { originalname, buffer } = f;
    var filename = originalname.toLowerCase().split(" ").join("-");

    filename = uuidv4()   "-"   filename;

    console.log(filename);

    const blob = bucket.file(filename);

    const blobStream = blob.createWriteStream({
      resumable: false,
    });

    blobStream.on("error", (err) => {
      res.status(500).send({ message: err.message });
      reject(err);
    });

    blobStream.on("finish", async (data) => {
      const publicUrl = format(
        `https://storage.googleapis.com/${bucket.name}/${blob.name}`
      );

      try {
        await bucket.file(filename).makePublic();
        resolve(publicUrl);
      } catch (err) {
        console.log("failed to make it public");
        reject(err);
      }
    });

    blobStream.end(buffer);
  });
};

exports.upload = async (req, res) => {
  const urlList = [];
  await processFile(req, res); //multer

  for (var i = 0; i < req.files.length; i  ) {
    if (!req.files[i]) {
      return res.status(400).send({ message: "Please upload a file!" });
    }

    const publicUrl = await uploadFile(req.files[i]);
    urlList.push(publicUrl);
  }

  return res.status(200).send({
    message: "Uploaded the files successfully",
    url: urlList,
  });
};


  • Related