If you were to aim to optimise the script, I’d probably want to have a map of PDF name to Tap Forms record ID. You can do a retrieve of a record by key/record ID via the script so if you precomputed a map of these keys or used the record ID import mode for Tap Forms to import the records then it’ll be a single retrieve for retrieving the record (form_record_id is the field in the CSV file which if present will be prepended with a rec- prefix and allow you to use form.getRecordWithId). The horse has likely already bolted for this one but something to consider for future projects, so let’s go ahead with the other suggestion: PDF attachment name in a script field.
If you have the PDF attachment name in a script field, you could use the getRecordFromFormWithKey function in my script manager. The method signature looks like this:
getRecordFromFormWithKey(formName, keyFieldId, keyValue, createIfMissing = true, earlyTermination = true, alwaysScanOnMiss = false)
It creates in Javascript an index on a first pass and then does looks up from there (set earlyTermination to false and alwaysScanOnMiss to true). When you’re in a tight loop this should improve performance by doing the record loop once to build the index and then you can do a similar sort of roughly constant time retrieval for matching records. It’s still two loops but you remove the nesting and replace it with a more optimised data structure.
First step is to create a new script field in your Contracts form and in it you want to add in the code we use to grab the filename from the PDF:
record.getFieldValue('fld-e870153bd0a647c9823ca998c213d1fd')[0].filename;
You’ll need to tick the “Update records when saving” option when creating that to populate the new field in all of your record. Essentially we’re just copying the filename as a new field. At this point you might also want to setup a search to look for records that have this field empty because that seems likely a bug. You’ll also need the field ID from the form panel (underneath the “Description” field) which I refer to later as “fld-scriptfieldidhere” that you’ll need to change.
Using the code you provided as a basis, something like this should get you some of the way there:
document.getFormNamed('Script Manager').runScriptNamed('getRecordFromFormWithKey');
function Update_Records() {
var csvForm = document.getFormNamed("csv");
// Contracts
var keyword_id = 'fld-a2126cbe512646e9ba144fb5a90b06dc';
var pdf_id = 'fld-3ea77ccc18604174b722ece105965c44';
// get use fixed field Id
var csvPdf_id = 'fld-4bcd0f1fba5c4178bb8d10a112b17489';
var csvKeyword_id = cvsForm.getFieldNamed('Keyword').getId();
// Loop over all csv entries
for (entry of csvForm.getRecords()) {
// get pdf file name of CSV record
var csvPdfName = entry.getFieldValue(csvPdf_id);
// replace spaces with underscores
csvPdfName = csvPdfName.replace('/ /g', '_');
console.log("Processing: " + csvPdfName);
contract = getRecordFromFormWithKey("Contracts", "fld-scriptfieldidhere", csvPdfName, false, false, true);
if (!contract) {
console.log('Unable to find matching PDF record: ' + csvPdfName);
continue;
}
console.log("Found match: " + csvPdfName);
// Update contract record
var type_of_agreement_id = 'fld-6af499ed439143b297828643341d939b'
contract.setFieldValue(type_of_agreement, 'Licensing Agreement')
// This should “replace” keyword or keywords in a selected record
var agreement_keywords_id = 'fld-a2126cbe512646e9ba144fb5a90b06dc';
contract.setFieldValue(agreement_keywords_id, entry.getFieldValue(csvKeyword_id));
}
document.saveAllChanges();
return 'done';
}
Update_Records();
We’ve still got the outer loop that iterates over the incoming CSV form, the “Contracts” loop is removed and replaced with the call to getRecordsFromFormWithKey which internally does a loop for you but also builds an index in memory that should make subsequent accesses quicker. Watch your memory usage in Activity Monitor but you’ve got 64GB of RAM so we should be fine. The script is finding the record for you so the code that lived inside your inner for loop moves up a level though there is a check to see if we got a record back. I did some minor changes to set the keyword based on the CSV form as an example of how I think that to work.
One thing I’ve done in scripts like this is put in a field for when it was processed to be able to skip it and also a counter to limit how many records are processed. This is useful for debugging scripts and being able to progressively execute it to get an idea of it:
let minTime = new Date().getTime() - 86400000; // one day
let processed = 0;
let skipped = 0;
for (...) {
let previousDate = entry.getFieldValue('fld-previousdateidhere');
if (previousDate && previousDate.getTime() > minTime) {
skipped++;
continue;
}
entry.setFieldValue('fld-previousdateidhere', new Date());
processed++;
if (processed > 100) {
break;
}
// your existing for loop logic here
}
This uses an extra field and updates when the script is run to set it that way the next time you run the script, it skips past records it’s already “processed” so to speak and moves onto the next batch of 100. Instead of handling the date logic in code, you could also tie this into a saved search as well so that Tap Forms only gives you the candidate records.