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

'AngularJS' filtering feature

I am dealing with an array of objects and I need to extract a specific value when a key is passed in the 'filter' function. Despite my best efforts, the controller code snippet provided below returns an undefined response. Can someone please assi ...

What are the steps to successfully submit my form once all the validation requirements have been met?

I successfully completed the validation process, but I am encountering an issue when trying to submit the form. An error message pops up indicating that there is an error related to a specific field (e.g., special characters being used). However, even when ...

What is the best way to extract text from a dynamically changing element using jQuery?

I've been struggling with a coding issue. Despite trying numerous approaches, I keep encountering the same problem where every new button I add ends up having the same text or, alternatively, nothing seems to work as expected. $j serves as my variabl ...

Searching for data in Node.js using Mongoose and dates

I'm in search of a way to execute a specific query with mongoose. In my mongodb database, I have data structured like this: "startDateTime" : ISODate("2017-03-22T00:00:00.000Z"), "endDateTime" : ISODate("2017-03-27T00:00:00.000Z"), My goal is to r ...

Setting up Scss and purgeCss configuration in Next.js custom postCSS configuration: A step-by-step guide

My current project is using Scss in combination with Bootstrap for design. I have implemented purgeCss to remove unused Css, and customized my postcss.config.js file as follows: module.exports = { plugins: [ "postcss-flexbugs-fixes", [ " ...

Triggering a JavaScript function upon the alteration of a Dojo auto-complete widget's value

I'm encountering an issue with calling a javascript function when the value of a Dojo auto completer changes. Despite trying to call the function through the "onChange" attribute, it doesn't work as expected. Within the javascript function, my ...

What is the process for determining the estimated location of a queued event within a JavaScript Engine's event queue?

Imagine a multitude of events being created and added to the event queue of a Javascript engine. Are there any techniques or recommended practices in the industry to predict the order in which a specific event will be added to the queue? Any knowledge or ...

Steer clear of encountering the "$digest already in progress" issue

A custom directive named 'myPagination' has been implemented, which encapsulates the functionality of the UI Bootstrap's pagination directive. angular.module('my-module') .directive('myPagination', ['$filter' ...

Can someone provide guidance on how to send serialized data using a jQuery.getScript() request?

Is it feasible to make a request for an external JS file while simultaneously sending serialized data in that same request? I want to provide some values to validate the request, but without including those values in the request URL. Upon receiving the po ...

Passing NextJS props as undefined can lead to unexpected behavior and

Struggling with dynamically passing props to output different photo galleries on various pages. One of the three props works fine, while the others are undefined and trigger a warning about an array with more than one element being passed to a title elemen ...

Executing a JQuery click event without triggering a page refresh

I'm dealing with a basic form on a webpage <div class="data-form"> <p>Are you hungry?</p> <form> <label class="radio-inline"><input type="radio" name="optradio" value="yes">Yes</label> ...

Adding an id to a ul tag using JavaScript

I am trying to dynamically add an ID called "myMenu" using JavaScript to a ul element for a search filter. Unfortunately, I am unable to directly access the ul tag to change it, so I need to do it via JavaScript. As I am new to JavaScript, I am looking t ...

Using Vue.js to link and update dynamic form fields

I have developed a dynamic set of form inputs utilizing vue.js, where the form inputs are generated from an external list of inputs. My challenge lies in figuring out how to bind the input values back to the vue model, enabling the vue instance to access ...

Leverage recursion for code optimization

I'm currently working on optimizing a function that retrieves JSON data stored in localStorage using dot notation. The get() function provided below is functional, but it feels verbose and limited in its current state. I believe there's room for ...

What is the best way to only buffer specific items from an observable source and emit the rest immediately?

In this scenario, I have a stream of numbers being emitted every second. My goal is to group these numbers into arrays for a duration of 4 seconds, except when the number emitted is divisible by 5, in which case I want it to be emitted immediately without ...

Tips on extracting the ID number prior to locating an element by its ID using Python Selenium

I am currently attempting to automate sending LinkedIn connection requests using Python with Selenium. However, I am facing an issue where the ember number value keeps changing every time I try to copy the id of the button. Sometimes it shows as #@id=" ...

Issue with MaterialUI value prop not updating after dynamic rendering of components when value state changes

As I dynamically generate Material UI form components, I encounter an issue with updating their values. The value prop is assigned to a useState values object, and when I update this object and the state, the value in the object changes correctly but the M ...

Error Alert: jQuery Ajax Not Executing

Looking to send form data to PHP using jQuery. Check out the code below. -------------HTML FORM-------------- <div id="createQuestionBlock"> <form id="createQuestionForm" action="" method="POST"> Question Code: <input id="code" ...

Can the HTML attributes produced by AngularJS be concealed from view?

Is there a way to hide the Angular-generated attributes such as ng-app and ng-init in the HTML code that is output? I want to present a cleaner version of the HTML to the user. Currently, I am using ng-init to populate data received from the server, but ...

Vite build error: TypeError - Unable to access properties of null while trying to read 'useContext'

I used the following component imported from material-ui : import Paper from '@mui/material/Paper'; After running npm run build followed by npm run preview, I encountered an error in the console: Uncaught TypeError: Cannot read properties of n ...