gas-db
is a wrapper library for Google Apps Script that simplifies working with Google Sheets. It provides an intuitive API to handle CRUD operations such as retrieving, searching, inserting, updating, and deleting data in sheets.
- Access and manipulate sheet data as JSON-like objects
- Simple and efficient API for CRUD operations
- Manage multiple sheets easily
- Use column names as keys for data manipulation
This library is already published as an Apps Script library. Follow the steps below to include it in your project:
-
Open your Apps Script project
Open the Google Apps Script editor and create a new project. -
Add the library
In the script editor, go to the "Libraries" section, and enter the following script ID:
1-oNObQAV_UrShtdZWEy8FwqmjGpD0-kVxWw-VdZdg0Dmx4xPs9Jp0-5Z
-
Select a version
Choose the latest version from the dropdown menu. -
Save
Click "Save" to add the library to your project.
Using gas-db
reduces boilerplate code, simplifies common operations, and allows developers to focus on business logic rather than low-level spreadsheet manipulations.
The comparison highlights how gas-db abstracts away complexities like range manipulation and data filtering, making the code cleaner and easier to maintain.
Creating an Instance of the Spreadsheet
Class. The following example demonstrates how to fetch a sheet and retrieve all data from it.
Without gas-db
:
function getAllDataWithoutGasDb() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Stories");
const data = sheet.getDataRange().getValues();
Logger.log(data);
}
With gas-db
:
function getAllDataWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.at("Stories");
const data = sheet.findAll();
Logger.log(data);
}
The Spreadsheet().from(scriptId)
method allows you to connect to a different Google Spreadsheet by providing its script ID. This is particularly useful when you need to work with spreadsheets other than the active one.
Without gas-db
:
function accessAnotherSpreadsheetWithoutGasDb() {
const anotherSpreadsheet = SpreadsheetApp.openById("ANOTHER_SPREADSHEET_ID");
const sheet = anotherSpreadsheet.getSheetByName("Stories");
const data = sheet.getDataRange().getValues();
Logger.log(data);
}
With gas-db
:
function accessAnotherSpreadsheetWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet().from("ANOTHER_SPREADSHEET_ID");
const sheet = spreadsheet.at("Stories");
const data = sheet.findAll();
Logger.log(data);
}
Retrieve only the data that matches specific conditions.
Without gas-db
:
function findDataWithoutGasDb() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Stories");
const data = sheet.getDataRange().getValues();
const results = data.filter(row => row[0] === "Adventure"); // Assuming "Title" is in the first column
Logger.log(results);
}
With gas-db
:
function findDataWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.at("Stories");
const results = sheet.find({ Title: "Adventure" });
Logger.log(results);
}
Add new data to the sheet.
Without gas-db
:
function insertDataWithoutGasDb() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Stories");
sheet.appendRow(["New Story", "John Doe"]); // Assuming Title and Author are the only columns
}
With gas-db
:
function insertDataWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.at("Stories");
sheet.insert({ Title: "New Story", Author: "John Doe" });
}
Update existing data based on specific conditions.
Without gas-db
:
function updateDataWithoutGasDb() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Stories");
const data = sheet.getDataRange().getValues();
const updatedData = data.map(row => {
if (row[1] === "John Doe") { // Assuming "Author" is in the second column
row[0] = "Updated Story"; // Update the "Title"
}
return row;
});
sheet.getRange(1, 1, updatedData.length, updatedData[0].length).setValues(updatedData);
}
With gas-db
:
function updateDataWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.at("Stories");
const newData = { Title: "Updated Story" };
const conditions = { Author: "John Doe" };
sheet.update(newData, conditions);
}
Insert data if it doesn't exist, otherwise update it.
Without gas-db
:
function upsertDataWithoutGasDb() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Stories");
const data = sheet.getDataRange().getValues();
const existingRowIndex = data.findIndex(row => row[0] === "Dynamic Story"); // Assuming "Title" is in the first column
if (existingRowIndex !== -1) {
// Update the row
const range = sheet.getRange(existingRowIndex + 1, 1, 1, data[0].length);
range.setValues([["Dynamic Story", "Jane Doe"]]);
} else {
// Insert new data
sheet.appendRow(["Dynamic Story", "Jane Doe"]);
}
}
With gas-db
:
function upsertDataWithGasDb() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.at("Stories");
const data = { Title: "Dynamic Story", Author: "Jane Doe" };
const conditions = { Title: "Dynamic Story" };
sheet.upsert(data, conditions);
}
Create a new sheet if it doesn't already exist.
function createOrFindSheet() {
const spreadsheet = new gasdb.Spreadsheet();
const sheet = spreadsheet.createOrFindSheet("NewSheet");
}
When working with a Google Sheet, gas-db
assumes by default that the first row (1) contains the headers (column names). These headers are used as keys when processing the data. However, if your data uses a different row as the header (e.g., the second or third row), you can adjust this behavior by specifying the hI (headerIndex) parameter.
- Define which row contains the column headers when interacting with a sheet.
- Allows flexible data processing when headers are not in the first row.
- Prevents manual pre-processing of sheets with non-standard header rows.
Specifying a Custom Header Index
function customHeaderIndex() {
const spreadsheet = new gasdb.Spreadsheet();
// Access a sheet with headers in the 2nd row
const sheet = spreadsheet.at("Stories", 2);
// Retrieve all data, using the 2nd row as keys for the data objects
const data = sheet.findAll();
Logger.log(data);
}
In this example:
- If the sheet "Stories" has headers in the 2nd row, specifying hI = 2 ensures that the keys for the returned data objects correspond to the column names in row 2.
If you do not specify the hI parameter, gas-db will assume the header row is the first row (hI = 1).
function defaultHeaderIndex() {
const spreadsheet = new gasdb.Spreadsheet();
// Access the sheet assuming the headers are in the 1st row
const sheet = spreadsheet.at("Stories");
// Retrieve all data
const data = sheet.findAll();
Logger.log(data);
}
To use this library, ensure your project's manifest includes the following scope:
https://www.googleapis.com/auth/spreadsheets
In the Apps Script editor, go to "Project Settings" to explicitly define the scope and avoid errors.
When working with Google Sheets, you may encounter API errors, such as:
- 503 Service Unavailable: This error often occurs due to a temporary issue with the Google Sheets API.
-
Retry Logic: Implement a retry mechanism with exponential backoff. For example:
function retryWithBackoff(fn, retries = 5) { for (let i = 0; i < retries; i++) { try { return fn(); } catch (e) { if (i === retries - 1) throw e; const backoffTime = Math.pow(2, i) * 1000; Utilities.sleep(backoffTime); } } }
-
Sheet Rotation: If you frequently encounter rate limits or service interruptions, consider rotating between multiple sheets or breaking up large operations into smaller chunks.
For more details, refer to Google Sheets API Troubleshooting.
Note: Error handling strategies like these are not included in the gas-db library, as the library focuses on simplifying CRUD operations. Developers are encouraged to implement error handling based on their specific use cases.
- No, you don't need to change the script ID to use the library.
This library is distributed under the MIT License.
The Japanese documentation for this library can be found at docs/ja/README.md
.