Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Use the filename as the ID for an upload collection

default discord avatar
dimbreathjr9 months ago
3

If you don't specify an "id" field there will be an automatically generated id for each entry in a media collection, is it possible to default to the filename or does it require me to use hooks to achieve this?

  • default discord avatar
    nolow_591239 months ago

    You can use the filename as the ID with a beforeOperation hook, but there are some considerations:


    const Media = {
      slug: 'media',
      upload: {
        staticDir: 'media',
      },
      hooks: {
        beforeOperation: [
          async ({ args, operation }) => {
            if (operation === 'create' && args.req?.file) {
              // Use filename as ID (sanitized)
              const filename = args.req.file.name
              const nameWithoutExt = filename.replace(/\.[^/.]+$/, '')
              args.data.id = nameWithoutExt.toLowerCase().replace(/[^a-z0-9-]/g, '-')
            }
            return args
          }
        ]
      },
      // ... rest of config
    }


    Important:



    This will fail if you upload files with duplicate names


    Consider using a beforeChange hook instead to add the filename as a separate indexed field while keeping auto-generated IDs


    Or add a timestamp: args.data.id = \sanitizedName−{sanitizedName}-


    sanitizedName−{Date.now()}``




    The auto-generated ID is usually better for uniqueness.



    https://payloadcms.com/docs/hooks/collections#beforeoperation
  • default discord avatar
    dimbreathjr9 months ago

    hmm that makes sense, the reason i wanted to do this is because i want one of each file to be created, if a file with the same name is uploaded it should be overwritten instead

  • default discord avatar
    nolow_591239 months ago

    For overwriting duplicate files, here's a different approach using beforeValidate:


    hooks: {
      beforeValidate: [
        async ({ data, req, operation }) => {
          if (operation === 'create' && data.filename) {
            const nameWithoutExt = data.filename.replace(/\.[^/.]+$/, '')
            const sanitizedId = nameWithoutExt.toLowerCase().replace(/[^a-z0-9-]/g, '-')
            
            // Set the custom ID
            data.id = sanitizedId
            
            // Check if this ID already exists
            try {
              await req.payload.findByID({
                collection: 'media',
                id: sanitizedId,
              })
              
              // If we get here, file exists - convert to update
              req.context.overwriteExisting = sanitizedId
            } catch (e) {
              // File doesn't exist, proceed with create
            }
          }
          return data
        }
      ],
      beforeChange: [
        async ({ context, req, operation }) => {
          if (context?.overwriteExisting && operation === 'create') {
            // Delete the existing file
            await req.payload.delete({
              collection: 'media',
              id: context.overwriteExisting,
            })
          }
        }
      ]
    }

    This splits the logic: beforeValidate sets the ID and detects duplicates, beforeChange handles the deletion. The file gets replaced with the same ID, achieving the overwrite behavior you want.

Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.