Help

Upcoming database upgrades. Airtable functionality will be reduced for ~15 minutes at 06:00 UTC on Feb. 4 / 10:00 pm PT on Feb. 3. Learn more here

Automate changing the file name of an attachment

3733 20
cancel
Showing results for 
Search instead for 
Did you mean: 

Hey Airtable Community.

I need help with automating the repetitive task of manually changing the name of a file after it’s been uploaded into my base. As of right now, we have a user filling out a form, and after it’s submitted, I want that to trigger the name changing. I have a field that is automatically created with a formula based on information captured in the form that I want the name changed too.

I’ve been looking at using the Airtable automation feature, but after trying a bunch of things, I can’t get it to work (perhaps I’m just too new at this) I also feel like maybe using a script might be the answer, but I don’t know how to do that, and if that’s the path to get this to work, I’ll need your help too :slightly_smiling_face: . Ultimately, I’m not sure and was hoping you (the community) might know.

Thanks in advance everyone!

20 Replies 20

My guess is that you might be able to update an attachment’s filename with a custom JavaScript, but I’m not 100% sure about this. One of the JavaScript experts would need to chime in on this one.

If not, you could likely use JavaScript to simply re-upload the same attachment into the same field — but with a new filename. Since I’m not a JavaScript expert yet (although I’m working on it!), I don’t have a definitive script on how to do this. I think it would be as easy as grabbing the URL of the original attachment and then simply updating the attachment field with that same exact URL + the brand new file name. I’m sure that one of the JavaScript experts here would be able to come up with a script to do this.

In the meantime, since I don’t know how to do this with a script, my personal way of doing this is using Integromat. I grab the attachment and simply re-upload it to the attachment field again with the new name.

Below is an example screenshot of how to set this up in Integromat. This scenario will work perfectly, regardless of whether you have a single attachment or multiple attachments.

I am an Airtable developer and a registered Integromat partner, so if you need to hire an expert to help you set this up, please feel free to send me a message or contact me through my website at scottworld.com.

Screen Shot 2020-10-09 at 8.41.09 AM

(Note that the Integromat link above contains an affiliate link of mine, so I would make a referral fee if you start paying for Integromat.)

Welcome to the community, @Cameron_Goldberg! :grinning_face_with_big_eyes: While attachments can be manually renamed, Airtable’s scripting options—in the Scripting app, or in the scripting action in an automation—only allow you to set the filename when first adding an attachment with a script. There’s no option for changing the filename of an existing attachment.

That said, you could use a process similar to what @ScottWorld described: collect the current URL of the attachment, then submit that as a new attachment in the same field with the name you want to use. I just ran a test using an automation, and it works surprisingly well. (NOTE: this will only work for a single attachment, which sounds like it’ll work for your use case; if anyone needs multiple attachments renamed, the setup will require some more detailed tweaking which I don’t have time to explore at the moment.)

I made a new automation using the “When record matches conditions” trigger, with the condition being that the attachment field is not empty. The scripting action requires four input variables from the triggering record:

  • recordID - The record ID
  • filename - The filename property of the attachment field
  • fileURL - The URL property of the attachment field
  • newName - The new name that you wish to assign to the attachment

The code for the scripting action step is below. This finds the existing file extension for the attachment and uses that for the new name, so your new name formula should not include the extension. That way it doesn’t matter what file type someone attaches (.gif, .jpg, .pdf, etc) because the script just uses the current extension, and only changes the rest of the name.

// Setup
let config = input.config()
let table = base.getTable("Table Name")

// Get the extension and add it to the new name.
let parts = config.filename[0].split(".")
let ext = parts[parts.length - 1]
let newName = `${config.newName}.${ext}`

// Reattach the item with the new filename
await table.updateRecordAsync(config.recordID, {
    "Attachment Field Name": [{url: config.fileURL[0], filename: newName}]
})

This is so unbelievably helpful, thank you!!

I’m kinda blown away with how great your response once, trying to implement it now, but still new to the world of scripts so it’s taking a bit of trial in error.

With that being said, In my use case, for 80% of what we do, it will be with only one file that would be uploaded via the form, but in some cases roughly 20% of the time, we would have multiple files that would be uploaded in at the same time… is adjusting this script to include 2+ uploaded files an easy (ish) addition?

Glad to help! Tweaking the script to work with multiple files should be fairly easy. The question becomes: how do you want to distinguish between the files? Let’s say that your formula creates the name “myName”. Two files are attached:

someFile.jpg
someOtherFile.jpg

Because they both have the same extension, giving them the same filename “myName.jpg” would cause some confusion. It would be easy enough to resolve this by appending a number to your generated name, which would create the following new names:

myName-01.jpg
myName-02.jpg

Would that work?

Yes, this would work!!

I’m directing my new name field to a formula, it’ll give me the flexibility to work around any future use cases I can currently think of.

Such a great solution!

Here’s the modified script. This one only needs a single input variable: recordID, which is the ID if the triggering record. Everything else is collected by the script. You’ll need to customize the names of the fields that are queried/updated, but that should be pretty straightforward.

// Setup
let config = input.config()
let table = base.getTable("Table Name")
let query = await table.selectRecordsAsync()
let record = query.getRecord(config.recordID)

// Collect record data
let newPrefix = record.getCellValue("Custom name")
let files = record.getCellValue("Attachment")

// Get the extension and add it to the new name
let newFiles = []
for (let file of files) {
    let parts = file.filename.split(".")
    let ext = parts[parts.length - 1]
    let fileNumber = "0" + (files.indexOf(file) + 1)
    let newName = `${newPrefix}-${fileNumber}.${ext}`
    newFiles.push({url: file.url, filename: newName})
}

// Reattach the item with the new filename
await table.updateRecordAsync(record, {
    "Attachment": newFiles
})

Thank you so much for this, might have a few questions/problems when implementing.

Firstly,

On the current script, I’m getting this error message. Do you know what I might be doing wrong? I spent a good 25 min before reaching back out trying different things as I suspect this is easy, but I’m completely missing it…

TypeError: Invalid arguments passed to recordQueryResult.getRecord(recordId):
• recordId should be a string, not undefined
    at main on line 5

Secondly, I’m actually using multiple attachment fields for each file. So, when it comes to naming it 1,2, etc… I’m presuming the current script only points to one attachment field, but I currently use 2 (that might increase in the future to more). I’m sorry I didn’t recognize that before, the scripting world is new to me, so it only really cued in once I was connecting the rest of it.

Did you create an input variable named “recordID” that pulls the ID from the trigger step?

Screen Shot 2020-10-13 at 4.55.26 PM

Not a problem. You can still use the most recent script. Just make one automation per attachment field, with each one triggering off a single field, and making sure to update each script to read and update the appropriate field.

I got it working :slightly_smiling_face:

Your direction was unbelievably helpful, and allowed me to do something I didn’t think was initially possible.

Thank you so much for your help!!!

@Justin_Barrett

Just ran into a problem today with the script… thought i’d reach out and get your advice.

So, on the surface, the script is a game changer for us. It’s changing file names perfectly, it’s amazing!!!

In our use case, we’re re-naming files so that when a user downloads them, it’ll be in the correct format. The problem is occurring when we download the file. For some reason, if the script is active, it turns it into a “TextEdit Document” when it’s downloaded onto my computer (we’ve also tested out multiple computers). It is critical that the script doesn’t change the type of file, as it makes it unusable… :frowning:

IE:
This is an example when the script isn’t on and how it still is a real .MOV file (same happens with .mp4): image

This is the same file downloaded with the script on: image

Things i’ve tried:

  1. I’ve tried changing the file name on my computer to see if it was perhaps the naming convention I gave it, no effect.

More context (if helpful)

  • The files we’re directing towards this script are mp4, .mov files.
  • This is what the file name looks like, it still contains .MOV so i’m confused: image

I edited the script a bit since our last message to get it working with the #1 and #2 convention. So, here is what the live version i’m using looks like:

let config = input.config()
let table = base.getTable("Self Tapes Submissions")
let query = await table.selectRecordsAsync()
let record = query.getRecord(config.recordID)

// Collect record data
let newPrefix = record.getCellValue("newName1")
let files = record.getCellValue("Self Tape #1")
// Get the extension and add it to the new name
let newFiles = []
for (let file of files) {
    let parts = file.filename.split(".")
    let ext = parts[parts.length - 1]

    let newName = `${newPrefix}. ${ext}`
    newFiles.push({url: file.url, filename: newName})
}

// Reattach the item with the new filename
await table.updateRecordAsync(record, {
    "Self Tape #1": newFiles
})

I think I know the problem…

The script is adding a space between the “.” and the file extension…

so it’s coming out “. mp4” when it should come out “.mp4”.

When I out the old number thing, I must have left a space where it would have been. Do you know what I’d have to change to remove the space. I’m going to keep trying, but if it’s an easy thing for you to see that’d be super helpful!

Changed to

let newName = `${newPrefix}.${ext}`

It’s working now.

also, now that I see the problem, it was such an easy one staring me in the face. I’ll chalk this up to a learning curve to scripts.

Glad that you were able to solve the problem. I don’t know how that space got into the new name creation, but it’s not part of my original script above. Did you copy my script, or retype it from scratch?

Yeah, as I look at your original, it was def me.

I was testing things out a bit, and trying to make it work, so I might have mistakenly added the " ".

Glad it’s solved, great script!!!

matt-pwi
4 - Data Explorer
4 - Data Explorer

@Justin_Barrett 

I'm currently trying to implement this into my airtable base but it's throwing an error at me.

mattpwi_0-1673629108723.png

This is what the image file looks like after I run the automation. It changes the file name, but the file is unreadable. This was from me trying the first script you wrote out.

I tried the second script, but then it was telling me that 

"let query = await table.selectRecordsAsync()"
is deprecated.
 
mattpwi_1-1673629432582.pngmattpwi_2-1673629457029.png
 
So now I'm at a loss on how to make it work. I also don't know if this script will fix the issue of not being able to read the file after reuploading. Here is everything that I'm currently working with:
 
mattpwi_3-1673629491746.png
 
mattpwi_4-1673629534267.png
 
mattpwi_6-1673629607532.png
 
mattpwi_5-1673629581069.png
 
Any help you can provide on this matter would be greatly appreciated!

Okay, update on my issue. I noticed the name discrepancy between fileName-front and fileName.front. That was fixed. I also removed the image that got messed up from the first script and tried a fresh photo, everything works great now! 

 

I am still curious about the deprecated js line though. Will that be a problem in the future? I'm not well-versed in js yet.

Re: the "deprecated" warning, that's not about the command in its entirety, but the specific way that my original script is using it. Long story short, using that method without passing anything to it--meaning nothing inside the parentheses--used to be valid. However, it means that you're asking for *every* field from the table, which is an unnecessary resource drain if you only need a small number of fields.

The recommended (and, eventually, required) way is to pass an object that contains a list of the fields that you want to retrieve from the records. Here's a brief example; you can find more details in the documentation (click the "API" link at the bottom of the script editor):

const query = await table.selectRecordsAsync({
    fields: ["First Field", "Second Field"]
})

Unfortunately I'm not able to go back and edit my original post where the old method use exists, so I hope that this clarification will help others who find this thread as well.

Hello Justin,

I tried your first code, but I got the same error that matt-pwi. The script is renaming, however, the file seems to be broken. I reviewed the code but did not find where the issue is.

Nome ajustado > Field with the newName
Documento > Field with the attachment

Check video below to see all the details

Unfortunately I don't have time to dig into this very deeply and run any specific tests. The problem might stem from the fact that the filename that you're trying to use contains spaces. Then again, the example from @matt-pwi doesn't contain spaces and still apparently had errors, so that's a long shot.

My next hunch is that this could be fallout from the change to expiring URLs for attachments, but again, I don't have time to test this theory thoroughly.

I nearly said "Once my schedule lightens up" with a promise to come back to this, but the reality is that I have no idea when I could dig into this further. Sorry.