2
votes

I'm new with uploading files, I want to upload images of different products into Firebase storage and another file that required in the app, one product can have many images, so I want to create a folder for every product, the name of the folder will be the id of the product.

In code: I use @google-cloud/storage library to upload the file into firebase storage, but I search in documentation, no way that I can be able to create a folder then upload it to folder.

here my code :

I create middleware of multer to pass it in an endpoint, with check type of file.

const express = require("express");
const Multer = require("multer");
const { Storage } = require("@google-cloud/storage")


const storage = new Storage({
    projectId: process.env.PROJECT_FIREBASE_ID,
    keyFilename: "hawat-service.json",
});
const bucket = storage.bucket(process.env.BUCKET_NAME);

const multer = Multer({
    storage: Multer.memoryStorage(),
    fileFilter: (req, file, cb) => {
        checkFileType(req, file, cb);
    }
})


const checkFileType = (req ,file, cb) => {
    if (file.fieldname == 'cover' || file.fieldname == 'images') {
        if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
              req.error = new Error( "Only images are allowed")
            return  cb(null, false);
        }
    } else if (file.fieldname == 'card' || file.fieldname == 'licence') {
        if (!file.originalname.match(/\.(pdf|jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) {
           req.error = new Error("Only images and pdf are allowed")
            return  cb(null, false);

        }
    }
    return cb(null, true)
}


module.exports = (req, res, next) => {


    return multer.fields([{ name: 'cover', maxCount: 1 },
    { name: 'images', maxCount: 5 }, { name: 'card', maxCount: 1 },
    { name: 'licence', maxCount: 1 }
])
        (req, res, () => {
            if (req.error) return res.status(400).send( {message : req.error.message })
            next()
        })
       
}

the function to upload file is

const express = require("express");
const Multer = require("multer");
const { Storage } = require("@google-cloud/storage");


const storage = new Storage({
  projectId: process.env.PROJECT_FIREBASE_ID,
  keyFilename: "hawat-service.json",
});

const bucket = storage.bucket(process.env.BUCKET_NAME);

module.exports = {
  upload: async ( file) => {
    return new Promise((resolve, reject) => {
      let newFileName = `${file.originalname}_${Date.now()}`;
  
      let fileUpload = bucket.file(newFileName);

      const createStream = fileUpload.createWriteStream({
          metadata: {
              contentType: file.mimetype
          }
      });

      createStream.on('error', (error) => {
        console.log("error in uploading is" , error)
          reject('Something is wrong! Unable to upload at the moment.');
      });

      createStream.on('finish', () => {
          // The public URL can be used to directly access the file via HTTP.
          const url = `https://storage.googleapis.com/${bucket.name}/${fileUpload.name}`;
       
      //   storage.bucket(process.env.BUCKET_NAME).file(fileUpload.name).makePublic();
     

             resolve(url);
      });

      createStream.end(file.buffer);
  });
  

the endpoint is

  router.post('/add-product' , auth, multer , seller.onAddProduct)

the function onAddProduct is a function that can receive multiple files from the user.

So How can I create a folder for every product, then upload files in the folder?

also, How can I delete the folder after created it?

2
const newFileName = ${product_id}/${file.originalname}_${Date.now()}; - handaru

2 Answers

0
votes

Folders in Google Cloud Storage are not really a thing. As you can see in this documentation:

gsutil provides the illusion of a hierarchical file tree atop the "flat" name space supported by the Cloud Storage service. To the service, the object gs://your-bucket/abc/def.txt is just an object that happens to have "/" characters in its name. There is no "abc"directory, just a single object with the given name

So what you see as a folder in Cloud Storage is simply another object that is emulating a folder structure, what really matters are the object paths.

In your case there are 2 ways you can go about what you want to do, you can either:

  • Create an emulated empty directory by creating an object that ends in a trailing slash. For example, to create a subdirectory called foo at the root of a bucket, you would create an empty object (size 0) called foo/ and then upload the file with it's full path.

  • Simply upload the file with it's full path including the desired "subdirectory" and when you fetch it from GCS it will look like it is located at the emulated directory.

Personally I would use the latter, as you will achieve the same results with only 1 step instead of 2.

0
votes

I am not using the same method you are using but you could use my solution as a case study

  await storage.bucket(bucketName).upload(filename, {
        destination:"{Foldername}/{Filename}",
})