正在儲存資料

節省數據用量的方法

PUT 定義的路徑 (例如 fireblog/users/user1/<data>) 中寫入或取代資料
PATCH 更新已定義路徑的部分鍵,不必取代所有資料。
POST 將資料新增至 Firebase 資料庫的資料清單。每次傳送 POST 要求時,Firebase 用戶端都會產生專屬鍵,例如 fireblog/users/<unique-id>/<data>
刪除 從指定的 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'

更新後,Alan 和 Grace 的暱稱都已新增完畢:

{
  "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. 如果決定重試要求,請使用新資訊。Realtime Database 不會自動重試失敗的條件式要求。不過,您可以使用新值和 ETag,根據失敗回應傳回的資訊建構新的條件要求。

以 REST 為基礎的條件要求會實作 HTTP if-match 標準。不過,這兩者與標準有以下差異:

  • 每個 if-match 要求只能提供一個 ETag 值,不能提供多個。
  • 雖然標準建議所有要求都應傳回 ETag,但 Realtime Database 只會針對包含 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'

如果 DELETE 要求成功,系統會傳回 200 OK HTTP 狀態碼,以及包含 JSON null 的回應。

URI 參數

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

auth

auth 請求參數可存取受 Firebase Realtime Database Security Rules 保護的資料,且所有請求類型都支援這項參數。這個引數可以是 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,即可取得使用者可理解格式的資料。print=pretty 支援 GETPUTPOSTPATCHDELETE 要求。

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

寫入伺服器值

您可以使用預留位置值 (即具有單一 ".sv" 鍵的物件),在某個位置寫入伺服器值。該鍵的值是我們希望設定的伺服器值類型。 舉例來說,如要在建立使用者時設定時間戳記,可以執行下列操作:

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

"timestamp" 是唯一支援的伺服器值,代表自 UNIX Epoch 紀元時間起算的毫秒數。

提升寫入效能

如果我們要將大量資料寫入資料庫,可以使用 print=silent 參數來提升寫入效能,並減少頻寬用量。在正常寫入行為中,伺服器會以寫入的 JSON 資料做為回應。 指定 print=silent 時,伺服器會在收到資料後立即關閉連線,減少頻寬用量。

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

錯誤狀況

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

HTTP 狀態碼
400 錯誤的要求

下列其中一種錯誤情況:

  • 無法剖析 PUTPOST 資料。
  • 缺少 PUTPOST 資料。
  • 要求嘗試 PUTPOST 過大的資料。
  • REST API 呼叫的路徑中含有無效子項名稱。
  • REST API 呼叫路徑過長。
  • 要求含有無法辨識的伺服器值。
  • 查詢的索引未在「Firebase Realtime Database Security Rules」中定義。
  • 要求不支援指定的其中一個查詢參數。
  • 要求將查詢參數與淺層 GET 要求混合。
401 未經授權

下列其中一種錯誤情況:

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

保護資料

Firebase 提供安全語言,可供我們定義哪些使用者有權讀取及寫入資料的不同節點。詳情請參閱 Realtime Database Security Rules

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