Jun 16, 2023 05:35 AM
I have a script that runs in google apps script and deletes all the records in a airtable table one by one, since I am new to coding and don't know how to code can anyone help me to modify the script to delete the records in batches of 10. I used chat-gpt to generate the script.
The script that deletes airtable records is:
function deleteRecordsInBatches() {
var airtableApiKey = "API_KEY/ACCESS_TOKEN"; //Paste your apiKey or accessToken here
var baseId = "BASE_ID"; //Paste your baseId here
var tableName = "tab3"; //Paste your tableName
// Number of records to delete in each batch
var batchSize = 10;
var tableUrl = "https://api.airtable.com/v0/" + baseId + "/" + tableName;
var headers = {
"Authorization": "Bearer " + airtableApiKey,
"Content-Type": "application/json"
};
// Fetch the initial set of records
var recordsToDelete = fetchRecords(tableUrl, headers);
while (recordsToDelete.length > 0) {
var batchRecords = recordsToDelete.splice(0, batchSize);
// Delete records in the current batch
deleteBatchRecords(batchRecords, tableUrl, headers);
// Sleep for 1 second to avoid rate limit
Utilities.sleep(0);
// Fetch the next set of records
recordsToDelete = fetchRecords(tableUrl, headers);
}
}
function fetchRecords(tableUrl, headers) {
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(tableUrl, options);
var result = JSON.parse(response.getContentText());
return result.records;
}
function deleteBatchRecords(records, tableUrl, headers) {
var options = {
"method": "DELETE",
"headers": headers,
"muteHttpExceptions": true
};
records.forEach(function(record) {
var recordUrl = tableUrl + "/" + record.id;
UrlFetchApp.fetch(recordUrl, options);
});
}
Solved! Go to Solution.
Jun 16, 2023 12:11 PM
With the help of @kuovonne and @Stephen_Orr1 and chat-gpt, I was able to generate the answer.
Problem: The original script I provided deleted records one by one instead of in batches of 10, as required.
Solution: To modify the script and make it delete records in batches of 10, the following changes were made:
Introduced a batchSize variable: Added a batchSize variable to specify the number of records to delete in each batch. In this case, the value is set to 10.
Modified the fetchAllRecords function: Updated the fetchAllRecords function to retrieve all records from the Airtable table. The function now uses pagination to fetch records in chunks, considering the possibility of more than 100 records. The function keeps making requests with the appropriate offset until all records have been retrieved.
Updated the deleteBatchRecords function: Modified the deleteBatchRecords function to send a single request to delete multiple records at once. Instead of making individual requests to delete each record, the function builds a payload with the IDs of the records to delete and sends a single HTTP DELETE request to the Airtable API. This significantly improves efficiency by reducing the number of API calls.
Additional Features: In addition to the batch deletion functionality, the following extra features were added:
Rate Limit Handling: To avoid hitting the rate limit of the Airtable API, a sleep function (Utilities.sleep(1000)) was introduced after each batch deletion. It pauses the execution for 1 second to ensure compliance with the rate limit restrictions.
Error Handling (not fully implemented): The script currently lacks error handling code, which would be essential in a production-ready solution. It is important to check the response from the API and handle any errors appropriately, such as rate limit exceeded or network issues. The commented-out sections in the deleteBatchRecords function indicate places where you can add error handling logic based on the specific requirements of your application.
The updated script should now delete records from the Airtable table in batches of 10, with added rate limit handling and improved efficiency. You can post this solution on Stack Overflow as an answer to a question, but make sure to customize it further based on the specific needs of the asker and add appropriate error handling mechanisms.
The updated script is:
function deleteRecordsInBatches() {
var airtableApiKey = "API_KEY/ACCESS_TOKEN"; //Paste your apiKey or accessToken here
var baseId = "BASE_ID"; //Paste your baseId here
var tableName = "tab3"; //Paste your tableName
// Number of records to delete in each batch
var batchSize = 10;
var tableUrl = "https://api.airtable.com/v0/" + baseId + "/" + tableName;
var headers = {
"Authorization": "Bearer " + airtableApiKey,
"Content-Type": "application/json"
};
// Fetch all records to be deleted
var allRecords = fetchAllRecords(tableUrl, headers);
while (allRecords.length > 0) {
var batchRecords = allRecords.splice(0, batchSize);
// Delete records in the current batch
deleteBatchRecords(batchRecords, tableUrl, headers);
// Sleep for 1 second to avoid rate limit
Utilities.sleep(1000);
}
}
function fetchAllRecords(tableUrl, headers) {
var allRecords = [];
var offset = null;
do {
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var url = tableUrl;
if (offset) {
url += "?offset=" + encodeURIComponent(offset);
}
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
var records = result.records;
if (records && records.length > 0) {
allRecords = allRecords.concat(records);
}
offset = result.offset;
} while (offset);
return allRecords;
}
function deleteBatchRecords(records, tableUrl, headers) {
var options = {
"method": "DELETE",
"headers": headers,
"muteHttpExceptions": true
};
var recordIds = records.map(function(record) {
return record.id;
});
var payload = {
"records": recordIds
};
var payloadString = JSON.stringify(payload);
var batchUrl = tableUrl + "?records[]=" + recordIds.join("&records[]=");
var response = UrlFetchApp.fetch(batchUrl, options);
// Check the response and handle any errors if necessary
// ...
// Optional: Log the response for debugging
// Logger.log(response.getContentText());
}
Jun 16, 2023 06:38 AM
Thank you for explaining your coding background and how you obtained this code. Thank you also for formatting the code in a way that is legible.
It looks like the code is putting records into batches, and then passing the batch to the deleteBatchRecords() function, which then proceeds to process each record in the batch individually.
If you are interested in learning to code, I recommend looking at the documentation for deleting multiple records.
Jun 16, 2023 08:11 AM
The code currently getting all records for a specified table, then batching these records into batches of 10 records, then running a single API call per record in this batch. As you pointed out, this is ignoring the "batch into 10 records" logic as to Airtable, this looks like one API call per record regardless.
Instead, you'll need to loop through the records returned in your initial fetch and grab 10 records every loop to use as a query parameter with the https://airtable.com/developers/web/api/delete-multiple-records API call.
Side note - I know Airtable rest API docs are intended to be language agnostic but it would be so nice if Javascript examples were provided next to curl... It would immediately help answer questions like these and encourage more people to use the API (and doesn't Airtable want that? :D).
Jun 16, 2023 09:01 AM
Instead, you'll need to loop through the records returned in your initial fetch and grab 10 records
The script already puts the records in batches of 10.
var batchRecords = recordsToDelete.splice(0, batchSize);
it would be so nice if Javascript examples were provided next to curl... It would immediately help answer questions like these and encourage more people to use the API (and doesn't Airtable want that? :D).
A previous version of the API documentation did include JavaScript examples, and maybe even other languages. However, I think the JavaScript examples assumed that you had the library, so it wasn't very useful to me, as my first foray into using the API was via PHP. I imagine that Airtable decided that language specific examples were too much to maintain, especially since there was the possibility of using a library versus raw calls.
I totally get that seeing more examples would be helpful. On the other hand, I also understand the difficulties in writing documentation. In these cases I tend to use a mixture of reading documentation and searching for example code on the internet. Once you understand how to implement a fetch request in JavaScript, the documentation is sufficient. Getting to that point of knowing how to implement a fetch request is a whole different matter (and relates to whether or not you want to learn to code), and I currently think that self-teaching JavaScript via ChatGPT is problematic.
It would immediately help answer questions like these and encourage more people to use the API (and doesn't Airtable want that? :D).
I think it is debatable whether or not Airtable actually wants users to be using the API. An increase in API use doesn't necessarily cause an increase in paid subscribers. And there seems to be no way to purchase higher rate limits than 5 requests per second. SaaS platforms that really encourage API usage tend to have the ability to buy much higher rate limits. I think Airtable is more focused on increasing people who use Airtable directly (either through the app itself or via interfaces).
Jun 16, 2023 10:20 AM - edited Jun 16, 2023 10:21 AM
@kuovonne wrote:Instead, you'll need to loop through the records returned in your initial fetch and grab 10 recordsThe script already puts the records in batches of 10.
I suppose I could have worded this better. "Instead" here refers to the query parameter part as in "instead, construct a query parameter that includes a full batch of record IDs, per the docs."
A previous version of the API documentation did include JavaScript examples, and maybe even other languages. However, I think the JavaScript examples assumed that you had the library, so it wasn't very useful to me, as my first foray into using the API was via PHP.
I thought I remembered this being available... glad I'm not crazy! My first experience with server-side scripting was also in PHP building a health flexible spending account web app for employees of my university. Moment of silence for the LAMP stack...
Now that Node.js has native fetch(), importing libraries won't be necessary like it used to be. Examples would essentially be the same for browser or server JS.
I currently think that self-teaching JavaScript via ChatGPT is problematic.
I agree with this for the most part. ChatGPT gets some things wrong and straight up lies about the expected output of code in my experience. Maybe one day this won't be the case. I do think it is a fantastic tool for explaining complex code or strange syntax to newbies. It can aid in learning a language (yet not best practices) as long as you are inquisitive and want to know "why" and not just the means to an end.
To your last point, I can see this being a factor. And selfishly, I wouldn't want it to become such a major cost or opportunity for Airtable that it warrants being a paid feature (ahem Reddit!!). I also like empowering people with tech though and this stuff (like most things) is doable with the desire to learn. Better docs will increase users, then Airtable can offer paid higher RPS once they're hooked 🙂
Jun 16, 2023 12:07 PM
@kuovonne and @Stephen_Orr1 thank you so much for reaching out to help!!
Jun 16, 2023 12:11 PM
With the help of @kuovonne and @Stephen_Orr1 and chat-gpt, I was able to generate the answer.
Problem: The original script I provided deleted records one by one instead of in batches of 10, as required.
Solution: To modify the script and make it delete records in batches of 10, the following changes were made:
Introduced a batchSize variable: Added a batchSize variable to specify the number of records to delete in each batch. In this case, the value is set to 10.
Modified the fetchAllRecords function: Updated the fetchAllRecords function to retrieve all records from the Airtable table. The function now uses pagination to fetch records in chunks, considering the possibility of more than 100 records. The function keeps making requests with the appropriate offset until all records have been retrieved.
Updated the deleteBatchRecords function: Modified the deleteBatchRecords function to send a single request to delete multiple records at once. Instead of making individual requests to delete each record, the function builds a payload with the IDs of the records to delete and sends a single HTTP DELETE request to the Airtable API. This significantly improves efficiency by reducing the number of API calls.
Additional Features: In addition to the batch deletion functionality, the following extra features were added:
Rate Limit Handling: To avoid hitting the rate limit of the Airtable API, a sleep function (Utilities.sleep(1000)) was introduced after each batch deletion. It pauses the execution for 1 second to ensure compliance with the rate limit restrictions.
Error Handling (not fully implemented): The script currently lacks error handling code, which would be essential in a production-ready solution. It is important to check the response from the API and handle any errors appropriately, such as rate limit exceeded or network issues. The commented-out sections in the deleteBatchRecords function indicate places where you can add error handling logic based on the specific requirements of your application.
The updated script should now delete records from the Airtable table in batches of 10, with added rate limit handling and improved efficiency. You can post this solution on Stack Overflow as an answer to a question, but make sure to customize it further based on the specific needs of the asker and add appropriate error handling mechanisms.
The updated script is:
function deleteRecordsInBatches() {
var airtableApiKey = "API_KEY/ACCESS_TOKEN"; //Paste your apiKey or accessToken here
var baseId = "BASE_ID"; //Paste your baseId here
var tableName = "tab3"; //Paste your tableName
// Number of records to delete in each batch
var batchSize = 10;
var tableUrl = "https://api.airtable.com/v0/" + baseId + "/" + tableName;
var headers = {
"Authorization": "Bearer " + airtableApiKey,
"Content-Type": "application/json"
};
// Fetch all records to be deleted
var allRecords = fetchAllRecords(tableUrl, headers);
while (allRecords.length > 0) {
var batchRecords = allRecords.splice(0, batchSize);
// Delete records in the current batch
deleteBatchRecords(batchRecords, tableUrl, headers);
// Sleep for 1 second to avoid rate limit
Utilities.sleep(1000);
}
}
function fetchAllRecords(tableUrl, headers) {
var allRecords = [];
var offset = null;
do {
var options = {
"method": "GET",
"headers": headers,
"muteHttpExceptions": true
};
var url = tableUrl;
if (offset) {
url += "?offset=" + encodeURIComponent(offset);
}
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
var records = result.records;
if (records && records.length > 0) {
allRecords = allRecords.concat(records);
}
offset = result.offset;
} while (offset);
return allRecords;
}
function deleteBatchRecords(records, tableUrl, headers) {
var options = {
"method": "DELETE",
"headers": headers,
"muteHttpExceptions": true
};
var recordIds = records.map(function(record) {
return record.id;
});
var payload = {
"records": recordIds
};
var payloadString = JSON.stringify(payload);
var batchUrl = tableUrl + "?records[]=" + recordIds.join("&records[]=");
var response = UrlFetchApp.fetch(batchUrl, options);
// Check the response and handle any errors if necessary
// ...
// Optional: Log the response for debugging
// Logger.log(response.getContentText());
}