Hi everyone! ![]()
I’d like to share a script I’ve been using to automate data imports. It’s perfect for scenarios where you receive a CSV file (via form or upload) and need to automatically create multiple records in a target App based on that file.
What this script does:
- Triggers from a record that contains a CSV file.
- Downloads and parses the CSV (handling quotes and delimiters).
- Maps CSV columns to specific field IDs in a target App.
- Automatically links the new records to a specific “Exhibitor” or “Reference” name.
- Posts a summary comment on the original record when finished.
The Script:
/**
* TAPE SCRIPT: CSV Auto-Importer
* Description: Reads an attached CSV and creates records in a target App.
*/
const CONFIG = {
target_app_id: 12345, // ID of the App where records will be created
source: {
file_field_id: 11111, // Field ID containing the CSV file
reference_field_id: 22222 // (Optional) Field ID for a reference name (e.g. Exhibitor)
},
// Map CSV Columns to Target Field IDs. Use 'null' to skip a column.
csv_mapping: [
33331, // Column 0 -> Field ID
33332, // Column 1 -> Field ID
33333, // Column 2 -> Field ID
null, // Column 3 -> Skipped
33335 // Column 4 -> Field ID
],
target_reference_field_id: 44444 // Field ID in target App to store the reference name
};
// --- HELPER FUNCTIONS ---
function getFieldValueSafe(record, fieldId) {
if (!record) return null;
const target = record.data || record;
const sFieldId = String(fieldId);
if (target.fields && typeof target.fields.get === 'function') {
const f = target.fields.get(sFieldId);
return f ? f.value : null;
}
if (target.fields && Array.isArray(target.fields)) {
const found = target.fields.find(item => String(item.field_id) === sFieldId || String(item?.field?.field_id) === sFieldId);
if (found) return found.values !== undefined ? found.values : found.value;
}
return target[sFieldId] || null;
}
function parseCSVRow(row) {
const regex = /("((?:[^"]|"")*)"|[^,;]*)([,;]|$)/g;
const columns = [];
let match;
row = row.replace('\r', '');
while ((match = regex.exec(row)) !== null) {
if (match.index === regex.lastIndex) { regex.lastIndex++; }
if (match[1] === undefined && match[2] === undefined) break;
let value = match[1];
if (value && value.startsWith('"') && value.endsWith('"')) {
value = value.slice(1, -1).replace(/""/g, '"');
}
columns.push(value);
if (match[2] === "") break;
}
return columns;
}
// --- MAIN EXECUTION ---
async function runImport() {
console.log('--- Starting CSV Import ---');
const currentRecord = tape.Record.current || await tape.Record.get(typeof record_id !== 'undefined' ? record_id : current_record_id);
if (!currentRecord) {
console.error("⛔ Error: Record not found.");
return;
}
try {
const fileData = getFieldValueSafe(currentRecord, CONFIG.source.file_field_id);
const refValue = getFieldValueSafe(currentRecord, CONFIG.source.reference_field_id);
if (!fileData || fileData.length === 0) {
console.log("No file found in the specified field.");
return;
}
const fileObj = fileData[0].value || fileData[0];
const fileUrl = fileObj.download_url || fileObj.link || fileObj.url;
if (!fileUrl) throw new Error("File URL not found.");
// Resolve Reference Name
let referenceName = "Not Informed";
if (refValue) {
referenceName = Array.isArray(refValue) ? (refValue[0].display_value || refValue[0].value) : (refValue.display_value || String(refValue));
}
const response = await http.get(fileUrl);
let csvText = response.body || response.data;
const rows = String(csvText).split(/\r?\n/);
const dataRows = rows.slice(1); // Skips header row
let createdCount = 0;
let errorCount = 0;
for (let i = 0; i < dataRows.length; i++) {
const row = dataRows[i];
if (!row.trim()) continue;
try {
const columns = parseCSVRow(row);
const newRecordFields = {};
if (CONFIG.target_reference_field_id) {
newRecordFields[String(CONFIG.target_reference_field_id)] = referenceName;
}
CONFIG.csv_mapping.forEach((targetFieldId, index) => {
if (targetFieldId && columns[index] !== undefined) {
newRecordFields[String(targetFieldId)] = columns[index].toString().trim().replace(/^"|"$/g, '');
}
});
await tape.Record.create(CONFIG.target_app_id, { fields: newRecordFields });
createdCount++;
} catch (rowError) {
errorCount++;
console.error(`Error on row ${i + 2}: ${rowError.message}`);
}
}
await tape.Comment.create(currentRecord.id, `✅ **Import Finished**\n- Created: ${createdCount}\n- Errors: ${errorCount}`);
} catch (error) {
console.error("General Error:", error.message);
}
}
runImport();
Hope this helps someone! Feel free to ask if you need help with the mapping.
![]()