How can I ensure that each callback is passed a distinct UUID?

I am utilizing a package called multer-s3-transform to modify the incoming image before uploading it to my bucket. Below is the code snippet of how I am implementing this:

const singleImageUploadJpg = multer({
  storage: multerS3({
    s3: s3,
    bucket: "muh-bucket",
    acl: "public-read",
    key: function(req, file, cb) {
      const fileName = uuid.v4();
      cb(null, fileName);
    },
    shouldTransform: function(req, file, cb) {
      cb(null, true);
    },
    transforms: [
      {
        id: "original",
        key: function(req, file, cb) {
          cb(null, `${uuid.v4()}.jpg`);
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      },
      {
        id: "small",
        key: function(req, file, cb) {
          cb(null, `${uuid.v4()}_small.jpg`);
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      }
    ]
  }),
  limits: { fileSize: 50 * 1024 * 1024 }
}).single("image");

A concern I have encountered is that the uuid generated will always differ between the small and original versions. How can I pass down the value of const fileName = uuid.v4() to each callback so that both versions have the same name except for the _small appended to one version?

Answer №1

It appears that multer triggers the provided functions multiple times, leading to a deviation from Jim Nilsson's suggestion. Furthermore, you have highlighted an issue where the specified name for the file received in the transform callback is not retained.

There are two potential solutions based on the assumption that either the file object or the req object remains consistent across callbacks:

  1. Your own custom property
  2. Implementing a WeakMap

Custom Property Approach

You could attempt to attach it to the file/req objects (using file below) like so (refer to the *** comments):

const singleImageUploadJpg = multer({
  storage: multerS3({
    s3: s3,
    bucket: "muh-bucket",
    acl: "public-read",
    key: function(req, file, cb) {
      file.__uuid__ = uuid.v4();                   // ***
      cb(null, file.__uuid__);
    },
    shouldTransform: function(req, file, cb) {
      cb(null, true);
    },
    transforms: [
      {
        id: "original",
        key: function(req, file, cb) {
          cb(null, `${uuid.v4()}.jpg`);
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      },
      {
        id: "small",
        key: function(req, file, cb) {
          cb(null, `${file.__uuid__}_small.jpg`);  
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      }
    ]
  }),
  limits: { fileSize: 50 * 1024 * 1024 }
}).single("image");

Note that this approach may involve undocumented functionality, necessitating thorough testing upon library upgrades.

WeakMap Integration:

Alternatively, consider utilizing a WeakMap indexed by the file or req objects (utilizing file below):

const nameMap = new WeakMap();
const singleImageUploadJpg = multer({
  storage: multerS3({
    s3: s3,
    bucket: "muh-bucket",
    acl: "public-read",
    key: function(req, file, cb) {
      const fileName = uuid.v4();
      nameMap.set(file, fileName);                  
      cb(null, fileName);
    },
    shouldTransform: function(req, file, cb) {
      cb(null, true);
    },
    transforms: [
      {
        id: "original",
        key: function(req, file, cb) {
          cb(null, `${uuid.v4()}.jpg`);
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      },
      {
        id: "small",
        key: function(req, file, cb) {
          const fileName = nameMap.get(file); 
          nameMap.delete(file);               
          cb(null, `${fileName}_small.jpg`);  
        },
        transform: function(req, file, cb) {
          cb(
            null,
            sharp()
              .resize()
              .jpeg({ quality: 50 })
          );
        }
      }
    ]
  }),
  limits: { fileSize: 50 * 1024 * 1024 }
}).single("image");

Answer №2

One way to improve the code is by encapsulating it in a function and generating the UUID before invoking multer:

const uploadImage = (function()
{
    const uniqueId = uuid.v4();
    return multer({
        storage: multerS3({
            s3: s3,
            bucket: "my-bucket",
            acl: "public-read",
            key: function(req, file, cb) {
              const fileName = uniqueId;
              cb(null, fileName);
            },
            shouldTransform: function(req, file, cb) {
              cb(null, true);
            },
            transforms: [
              {
                id: "original",
                key: function(req, file, cb) {
                  cb(null, `${uniqueId}.jpg`);
                },
                transform: function(req, file, cb) {
                  cb(
                    null,
                    sharp()
                      .resize()
                      .jpeg({ quality: 50 })
                  );
                }
              },
              {
                id: "small",
                key: function(req, file, cb) {
                  cb(null, `${uniqueId}_small.jpg`);
                },
                transform: function(req, file, cb) {
                  cb(
                    null,
                    sharp()
                      .resize()
                      .jpeg({ quality: 50 })
                  );
                }
              }
            ]
        }),
        limits: { fileSize: 50 * 1024 * 1024 }
    }).single("image");
})();

Answer №3

Instead of repeatedly calling the uuid.v4 method in your handler, which generates different values each time, you should call it once and store the result in a variable.

const singleImageUploadJpg = ( function( my_uuid )
{
    // same functionality as before

})(  uuid.v4() );

After that, you can simply use this variable whenever needed.

cb(null, `${my_uuid}.jpg`);
// ...
cb(null, `${my_uuid}_small.jpg`);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to transform a .pcm file to a wav file using node.js?

I'm working on a project that generates a pcm file from a stream and saves it after the stream finishes. Now, I am looking for a way to convert this .pcm file to a .wav or another audio format using an npm package. Can anyone suggest a solution or poi ...

Triggering the open() function within an Ajax request

Upon experimenting with the method open(), I discovered that it requires a URL file as an argument. For instance, I have two functions named generateGeometricShapes() and colorShapes(). I am contemplating whether I should create separate files for each fu ...

AngularJS: Index not refreshing after deletion of array item(s) using their indexes

I am attempting to eliminate a specific item from an array variable within AngularJS's scope by using the item's index. If you believe this question is a duplicate, please check out the footnote links for related questions that were not exactly ...

Mobile Menu in wordpress stays visible after being clicked

I recently created a one-page layout that includes some links. However, when I view the site on my smartphone and open the main menu using the button to click on a link (which scrolls within the same page), I noticed that the mobile menu remains visible a ...

Changing the stroke color in between drawing on an HTML5 Canvas

I have been experimenting with a basic JavaScript snippet to showcase an unusual HTML5 canvas behavior I've encountered. Every 100ms, I am drawing the same set of strokes but in a different sequence. Strangely, some of the strokes change color interm ...

Discovering a secondary identification for an HTML element that contains multiple IDs

I have a jsp page in my project with the following html structure: <table id="hor-minimalist-a" class="campos"> <thead> <tr> <th>Campo</th> <th>#</th> </tr> </thead> <tfoot ...

Is there a way to retrieve the value from an input box?

<td class="stockQuantity"> <input class="form-control" id="Cart1" name="qty_req" required="required" type="text" value=""><br> <button type="button" o ...

What is the method for executing a for loop in AngularJS without relying on HTML elements?

I'm creating an application in AngularJS where the structure requires me to execute a for each loop without using any HTML elements or div tags with ng-repeat. In Django, we typically use the following syntax: {% for item in list %} {{ item }} {% ...

The issue arises when attempting to use a JavaScript marker within an array, as it

At the moment, I am in the process of building a website that includes a Google map showcasing my custom markers. Each marker is linked to a specific URL, and the connection is straightforward (as shown with one of my markers below) - var image = 'p ...

Increase the Step Size of an HTML Number Input by Holding Down the Time

Is there a way to implement increasing increment/step size for number inputs in HTML based on how long the user holds the stepper arrows? For instance, starting at step size=1 and gradually ramping up to larger increments like 5, 10, 20, etc. after holdin ...

Include onload to element without running it in Puppeteer

I am currently developing a web scraping tool using Puppeteer. Once the webpage is fully loaded, I need to update the HTML code and include an onload event for certain elements. The issue is that in Puppeteer, the onload event is actually triggered automa ...

Is there a way to update a child component in React when the parent state changes, without utilizing the componentWill

I am currently working on developing a JSON editor using React, but I am facing an issue with the library I am utilizing not having a componentWillReceiveProps hook. As someone relatively new to React, I am trying to find a way to automatically update th ...

Importing a module directly from the umd distribution may yield a distinct outcome compared to importing it

Within my Vite/Vue3 application, I am importing two identical umd.js files: One is located at node_modules/foo/bar/dist/foobar.umd.js (imported with alias @foo = node_modules/@foo). The second .umd.js file can be found at <root dir>/foo/bar/dist/ ...

Arrange the JSON object according to the date value

I am working on a JavaScript project that involves objects. Object {HIDDEN ID: "06/03/2014", HIDDEN ID: "21/01/2014"} My goal is to create a new object where the dates are sorted in descending order. Here's an example of what I want: SortedObject ...

Javascript Library Issue: "Implicitly Declared Type 'Any' Error"

I am currently in the process of developing a JavaScript library that will interact with an API. My goal is to create a module that can be easily published on npm and utilized across various frameworks such as Angular or React. Below is the code snippet fo ...

Is there a way to handle button click event when utilizing this.props.children in React?

I have recently completed a React component that serves as a modal wrapper. The content for this modal is passed through the props.children property. Inside the content, there is a button that, when clicked, should trigger an event in the parent component. ...

Utilizing JavaScript for manipulating arrays and displaying images

After asking this question previously without a satisfactory solution, I am hoping to provide better clarification. Imagine having an array with 3 items and it lands on 0 - a code is set up to display this in a div. Now, I want the image to be shown righ ...

Attempting to generate a fresh document by duplicating the data from a specific variable

Currently attempting to generate a new csv file within a specific directory. The goal is to save the data of a variable inside the created csv file: handleRequest(req, res) { var svcReq = req.body.svcReq; var csvRecData = JSON.stringify(req.bod ...

Having trouble integrating VueX store and router into Mocha tests

Latest Update To view the issue on VueX git repository that has been created, please follow this link: https://github.com/vuejs/vuex/issues/1509 If you want to replicate the problem, here is the link to the repository: https://github.com/djam90/vuex-vue- ...

Troubles arising while submitting data from AngularJS to Amazon S3

I am currently in the process of developing an application using the MEAN (MongoDB, Express, AngularJS, node.js) stack where I need to upload image files to Amazon S3. Here is my approach: Initially, an http get request is sent to my API which outlines th ...