Firebase 上建立新專案
建立過程依序會詢問專案名稱、是否在 Firebase 上啟用 Gemini、是否啟用 Google Analytics
建立 Firebase RealTime Database
產品類別 => 資料庫和儲存空間 => NoSQL => Realtime Database 點選建立資料庫
選擇資料庫位置,選擇新加玻 (asia-southeadt1)
安全性規則,預設為鎖定模式
Realtime Database 建立完成,紅線為 Readtime Database URL,GAS 會透過它來存取
訂閱方案 - Spark Plan
使用雲端服務最重要的了解帳單費用,Spark Plan 訂閱是 free 的,但 Realtime Database 有使用量限制,萬一到達使用量限制服務就會停止,下圖為 Realtime Database 使用限制,關於 Spark Plan 其他服務使用限制,可以參考官方網站 - Pricing
Google Apps Script CRUD
從 GAS 連線至 Realtime Database 是透過 ScriptApp.getOAuthToken() 取的個人身份來進行驗證,該筆記只著重在 Realtime Database CRUD 操作是沒有問題,但萬一該存取 Realtime Database 會開放,改用 GAS 第三方套件 OAuth2 搭配 Firebase 服務帳號來使用會比較適合
設定 oauth 授權範圍,Google Apps Script Project settings => 啟用 [在編輯器中顯示「appsscript.json」資訊清單檔案]
在編輯器中出現「appsscript.json」資訊清單檔案並加入 oauth 授權範圍
appsscript.json 完整資訊,oauthScopes 為手動加入
{
"timeZone": "Asia/Taipei",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/firebase.database"
]
}
在指令碼指令內建立 Realtime Database URL
CRUD Code
/**
* 從 Script Properties 取得 Firebase 資料庫網址
* @constant {string}
*/
const FIREBASE_URL = PropertiesService.getScriptProperties().getProperty("FIREBASE_URL");
/**
* 寫入或覆寫資料 (PUT)
* 執行此操作會將指定路徑下的資料完全替換為傳入的 data。
* * @param {string} path - Firebase 資料庫中的目標路徑(不含 .json 後綴)
* @param {Object} data - 欲寫入或覆寫的 JSON 資料物件
* @returns {Object} Firebase 伺服器回傳的 JSON 解析物件
*/
function writeDataBuiltIn(path, data) {
const token = ScriptApp.getOAuthToken();
const url = `${FIREBASE_URL}${path}.json`;
const options = {
method: "put", // 使用 put 進行資料寫入
contentType: "application/json",
headers: {
Authorization: 'Bearer ' + token
},
payload: JSON.stringify(data),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
console.log("寫入狀態: " + response.getResponseCode());
return JSON.parse(response.getContentText());
}
/**
* 讀取資料 (GET)
* 從指定的資料庫路徑讀取目前的資料。
* * @param {string} path - Firebase 資料庫中的目標路徑(不含 .json 後綴)
* @returns {Object|null} Firebase 伺服器回傳的 JSON 解析物件(若該路徑無資料則為 null)
*/
function readDataBuiltIn(path) {
const token = ScriptApp.getOAuthToken();
const url = `${FIREBASE_URL}${path}.json`;
const options = {
method: "get", // 使用 get 進行存取
headers: {
Authorization: 'Bearer ' + token
},
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
console.log("寫入狀態: " + response.getResponseCode());
return JSON.parse(response.getContentText());
}
/**
* 部分更新資料 (PATCH)
* 只會你傳入的欄位,不會覆寫原本存在的其他欄位。
* * @param {string} path - Firebase 資料庫中的目標路徑(不含 .json 後綴)
* @param {Object} data - 要更新的 JSON 資料物件
* @returns {Object} Firebase 伺服器回傳的 JSON 解析物件(包含已更新的欄位資料)
*/
function updateDataBuiltIn(path, data) {
const token = ScriptApp.getOAuthToken();
const url = `${FIREBASE_URL}${path}.json`;
const options = {
method: "patch", // 使用 patch 進行部分更新
contentType: "application/json",
headers: {
Authorization: 'Bearer ' + token
},
payload: JSON.stringify(data),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
console.log("寫入狀態: " + response.getResponseCode());
return JSON.parse(response.getContentText());
}
/**
* 刪除資料 (DELETE)
* 會刪除該路徑下的所有資料與子節點。
* * @param {string} path - Firebase 資料庫中的目標路徑(不含 .json 後綴)
* @returns {string} Firebase 伺服器回傳的回應字串(刪除成功通常會回傳 "null" 字串)
*/
function deleteDataBuiltIn(path) {
const token = ScriptApp.getOAuthToken();
const url = `${FIREBASE_URL}${path}.json`;
const options = {
method: "delete", // 使用 delete 刪除節點
headers: {
Authorization: 'Bearer ' + token
},
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch(url, options);
console.log("寫入狀態: " + response.getResponseCode());
return response.getContentText();
}
實際測試寫入
function testWriteDataBuiltIn() {
const userPath = "customers/user_123";
const userData = {
name: "陳大文",
email: "david@example.com",
membership: "VIP",
joinDate: Utilities.formatDate(new Date() , Session.getScriptTimeZone() , 'yyyy-MM-dd HH:mm:ss')
};
writeDataBuiltIn(userPath, userData);
console.log("寫入測試完成!請到 Firebase 後台查看結果。");
}
讀取
function testReadDataBuiltIn() {
const testPath = "customers/user_123";
const data = readDataBuiltIn(testPath);
if (data !== null) {
console.log("讀取成功!資料內容如下:");
console.log(JSON.stringify(data, null, 2));
} else {
console.log("讀取失敗,請檢查權限或路徑。");
}
}
更新
function testUpdateDataBuiltIn() {
const userPath = "customers/user_123";
// 假設原本資料有 name, email, membership。
// 我們現在只想升級他的 membership,並新增一個 points 欄位,保留原本的 name 與 email。
const updatePayload = {
membership: "VVIP", // 更新現有欄位
points: 500, // 新增原本沒有的欄位
lastUpdated: Utilities.formatDate(new Date() , Session.getScriptTimeZone() , 'yyyy-MM-dd HH:mm:ss')
};
updateDataBuiltIn(userPath, updatePayload);
console.log("更新完成!請去 Firebase 檢查 user_123 的資料,原本的名字應該還在。");
}
刪除function testDeleteDataBuiltIn() {
const userPath = "customers/user_123";
deleteDataBuiltIn(userPath);
console.log("刪除完成!該節點已經從 Firebase 移除了。");
}














沒有留言:
張貼留言