正在儲存資料

儲存資料的方式

PUT 將資料寫入或取代至定義的路徑,例如 fireblog/users/user1/<data>
PATCH 更新已定義路徑的部分鍵,而不替換所有資料。
POST 新增至 Firebase 資料庫中的資料清單。每當我們傳送 POST 要求時,Firebase 用戶端都會產生專屬金鑰,例如 fireblog/users/<unique-id>/<data>
DELETE 從指定的 Firebase 資料庫參考資料中移除資料。

使用 PUT 寫入資料

透過 REST API 進行的基本寫入作業為 PUT。為示範儲存資料的做法,我們將建構內含貼文和使用者的網誌應用程式。應用程式的所有資料會儲存在「fireblog」的路徑下,位於 Firebase 資料庫網址「https://docs-examples.firebaseio.com/fireblog」。

讓我們先將部分使用者資料儲存到 Firebase 資料庫。我們會使用不重複的使用者名稱儲存每位使用者,並且會儲存使用者的全名和出生日期。由於每個使用者都會有不重複的使用者名稱,因此改用 PUT 而不是 POST,因為我們已經有金鑰,不必建立金鑰。

我們可以使用 PUT,將字串、數字、布林值、陣列或任何 JSON 物件寫入 Firebase 資料庫。在這個案例中,我們會傳送一個 物件給該物件:

curl -X PUT -d '{
  "alanisawesome": {
    "name": "Alan Turing",
    "birthday": "June 23, 1912"
  }
}' 'https://docs-examples.firebaseio.com/fireblog/users.json'

將 JSON 物件儲存至資料庫後,系統會以巢狀方式將物件屬性自動對應至子項位置。前往新建立的節點時,會看到值「Alan Turing」。另外,我們也可以直接將資料儲存到子項位置:

curl -X PUT -d '"Alan Turing"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/name.json'
curl -X PUT -d '"June 23, 1912"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/birthday.json'

上述兩個範例 (同時寫入值與物件,並分別寫入子項位置),將使相同的資料儲存至 Firebase 資料庫:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    }
  }
}

成功的要求會以 200 OK HTTP 狀態碼表示,回應也會包含我們寫入資料庫的資料。第一個範例只會在正在觀看資料的用戶端上觸發一個事件,第二個範例則觸發兩個事件。請特別注意,如果資料已存在於使用者路徑,第一種方法會覆寫這類資料,但第二個方法只會修改每個個別子節點的值,而其他子項維持不變。PUT 相當於 JavaScript SDK 中的 set()

使用 PATCH 更新資料

使用 PATCH 要求,我們可以更新位置中的特定子項,而不會覆寫現有資料。讓我們使用 PATCH 要求,在使用者資料中加入杜林的暱稱:

curl -X PATCH -d '{
  "nickname": "Alan The Machine"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

上述要求會將 nickname 寫入 alanisawesome 物件,但不會刪除 namebirthday 子項。請注意,如果在這裡發出 PUT 要求,由於 namebirthday 不在要求中,因此已遭刪除。Firebase 資料庫中的資料如下所示:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    }
  }
}

成功的要求會以 200 OK HTTP 狀態碼表示,回應會包含寫入資料庫的更新資料。

Firebase 也支援多路徑更新。換句話說,PATCH 現在可以同時更新 Firebase 資料庫中多個位置的值,而這項強大功能能讓您將資料去標準化。透過多路徑更新功能,我們可以同時為 Alan 和 Grace 加上暱稱:

curl -X PATCH -d '{
  "alanisawesome/nickname": "Alan The Machine",
  "gracehopper/nickname": "Amazing Grace"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

本次更新後,小艾和小蕾也新增了暱稱:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

請注意,若嘗試透過包含的路徑編寫物件來更新物件,則會造成不同的行為。讓我們看看如果改為透過以下方式更新 Grace 和 Alan,會發生什麼情況:

curl -X PATCH -d '{
  "alanisawesome": {"nickname": "Alan The Machine"},
  "gracehopper": {"nickname": "Amazing Grace"}
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

這會產生不同的行為,也就是覆寫整個 /fireblog/users 節點:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

使用條件式要求更新資料

您可以使用條件式要求 (相當於交易的 REST),根據現有狀態更新資料。例如,如果您想增加支持票數,且想要確保計數可準確反映多筆同時認同的認同票數,請使用條件式要求將新值寫入計數器。而不是兩次寫入作業,讓計數器變更為相同次數,其中一項寫入要求會失敗,這時您可以使用新值重試要求。
  1. 如要對特定位置執行條件式要求,請取得該位置目前資料的專屬 ID,或取得 ETag。如果該位置的資料有所變動,ETag 也會跟著改變。您可以使用 PATCH 以外的任何方法要求 ETag。以下範例使用 GET 要求。
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    
    具體呼叫在標頭中呼叫 ETag 時,系統會在 HTTP 回應中傳回指定位置的 ETag。
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    10 // Current value of the data at the specified location
    
  2. 在下一個 PUTDELETE 要求中加入傳回的 ETag,即可更新明確符合該 ETag 值的資料。按照我們的範例,如要將計數器更新為 11,或大於 10 的初始擷取值大於 1,並在值不再相符時使要求失敗,請使用以下程式碼:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    
    如果指定位置的資料值仍為 10,則 PUT 要求中的 ETag 相符且要求成功,請將 11 寫入資料庫。
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    Cache-Control: no-cache
    
    11 // New value of the data at the specified location, written by the conditional request
    
    如果位置不再與 ETag 相符 (此時如有其他使用者將新值寫入資料庫),要求就會失敗,而且不會寫入位置。傳回回應包含新值和 ETag。
    HTTP/1.1 412 Precondition Failed
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    12 // New value of the data at the specified location
    
  3. 如果您決定重試要求,請使用新的資訊。即時資料庫不會自動重試失敗的條件要求。不過,您可以使用新的值和 ETag 來建構新的條件式要求,其中包含失敗回應傳回的資訊。

以 REST 為基礎的條件式要求會實作 HTTP if-match 標準。不過,這些 API 與標準的存在差異如下:

  • 每個比對要求只能提供一個 ETag 值,不能有多個。
  • 雖然標準標準建議所有要求都會傳回 ETag,但即時資料庫只會傳回內含 X-Firebase-ETag 標頭的 ETag。可降低標準要求的帳單費用。

此外,條件式要求也可能比一般 REST 要求慢。

正在儲存資料清單

如要為新增至 Firebase 資料庫參考資料的每個子項產生不重複的時間戳記型金鑰,我們可以傳送 POST 要求。針對我們的 users 路徑,定義自己的金鑰是合理的,因為每位使用者都有專屬使用者名稱。不過,當使用者在應用程式中新增網誌文章時,我們會使用 POST 要求自動產生每篇網誌文章的金鑰:

curl -X POST -d '{
  "author": "alanisawesome",
  "title": "The Turing Machine"
}' 'https://docs-examples.firebaseio.com/fireblog/posts.json'

我們的 posts 路徑現在具備下列資料:

{
  "posts": {
    "-JSOpn9ZC54A4P4RoqVa": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

請注意,因為我們使用了 POST 要求,所以系統自動產生 -JSOpn9ZC54A4P4RoqVa 鍵。成功的要求會以 200 OK HTTP 狀態碼表示,回應也會包含新增資料的鍵:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

移除資料

如要從資料庫中移除資料,我們可以傳送 DELETE 要求,其中包含要刪除資料的路徑網址。下列指令會從 users 路徑中刪除 Alan:

curl -X DELETE \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

200 OK HTTP 狀態碼會表示成功的 DELETE 要求,回應中會包含 JSON null

URI 參數

將資料寫入資料庫時,REST API 會接受下列 URI 參數:

auth

auth 要求參數可讓您存取受 Firebase 即時資料庫安全性規則保護的資料,而且所有要求類型都能支援。引數可以是 Firebase 應用程式密鑰或驗證權杖,我們會在使用者授權一節中說明。在以下範例中,我們會傳送含有 auth 參數的 POST 要求,其中 CREDENTIAL 是我們的 Firebase 應用程式密鑰或驗證權杖:

curl -X POST -d '{"Authenticated POST request"}' \
  'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

顯示

print 參數可讓我們指定資料庫的回應格式。在要求中加入 print=pretty,系統會以使用者可理解的格式傳回資料。GETPUTPOSTPATCHDELETE 要求支援 print=pretty

如要在寫入資料時抑制伺服器輸出內容,可以在要求中加入 print=silent。要求成功時,產生的回應會是空白,並由 204 No Content HTTP 狀態碼表示。GETPUTPOSTPATCH 要求支援 print=silent

寫入伺服器值

您可以使用預留位置值將伺服器值寫入特定位置,該預留位置是只含單一 ".sv" 鍵的物件。該鍵的值是我們要設定的伺服器值類型。 舉例來說,如要設定建立使用者時的時間戳記,可執行以下動作:

curl -X PUT -d '{".sv": "timestamp"}' \
  'https://docs-examples.firebaseio.com/alanisawesome/createdAt.json'

"timestamp" 是唯一支援的伺服器值,自 UNIX 紀元以來的時間,以毫秒為單位。

提升寫入效能

如果要將大量資料寫入資料庫,我們可以使用 print=silent 參數提高寫入效能並減少頻寬用量。在一般寫入行為中,伺服器會傳回寫入的 JSON 資料。如果指定 print=silent,伺服器會在收到資料後立即關閉連線,從而降低頻寬用量。

如果我們對資料庫發出許多要求,只要透過 HTTP 標頭傳送 Keep-Alive 要求,即可重複使用 HTTPS 連線。

錯誤狀況

在下列情況中,REST API 會傳回錯誤代碼:

HTTP 狀態碼
400 錯誤的要求

下列其中一項錯誤狀況:

  • 無法剖析 PUTPOST 資料。
  • 缺少 PUTPOST 資料。
  • 要求嘗試嘗試的 PUTPOST 資料過大。
  • REST API 呼叫路徑包含無效的子項名稱。
  • REST API 呼叫路徑過長。
  • 要求含有無法辨識的伺服器值。
  • Firebase 即時資料庫安全性規則並未定義查詢的索引。
  • 請求不支援指定的其中一個查詢參數。
  • 這項要求會混合查詢參數和淺層 GET 要求。
401 未授權

下列其中一項錯誤狀況:

找不到 404 找不到指定的 Firebase 資料庫。
500 內部伺服器錯誤 伺服器傳回錯誤。詳情請參閱錯誤訊息。
503 無法使用服務 指定的 Firebase 即時資料庫暫時無法使用,系統未嘗試要求。

保護資料

Firebase 的安全性語言可讓我們定義哪些使用者俱備不同資料節點的讀取和寫入權限。詳情請參閱即時資料庫安全性規則

我們已介紹如何儲存資料,接著就能在下一節中,瞭解如何透過 REST API 從 Firebase 資料庫擷取資料。