建立資料庫結構

本指南涵蓋資料架構的幾個重要概念,並 在 Firebase 即時資料庫中建構 JSON 資料的最佳做法。

要建立結構良好的資料庫,機構必須審慎顧慮。 最重要的是,您必須規劃資料儲存方式。 以簡化這項程序

資料的結構:這是 JSON 樹狀結構

所有 Firebase 即時資料庫資料都會儲存為 JSON 物件,您可以將資料庫想像成雲端託管 JSON 樹狀結構。與 SQL 資料庫不同的是,這個資料庫中沒有表格或記錄。將資料新增至 JSON 樹狀結構時,資料會在現有 JSON 結構中變成一個節點,且包含關聯的金鑰。您可以提供自己的金鑰 例如使用者 ID 或語意名稱 push() 方法。

如果您要建立自己的金鑰,金鑰必須採用 UTF-8 編碼, 為 768 個位元組,且不得包含 .$#[]/ 或 ASCII 控制項 字元數:0-31 或 127。您不能在值中使用 ASCII 控製字元

例如,假設即時通訊應用程式可讓使用者儲存 設定檔和聯絡人清單一般使用者設定檔位於路徑,例如 /users/$uid。使用者 alovelace 的資料庫項目可能 如下所示:

{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      "contacts": { "ghopper": true },
    },
    "ghopper": { ... },
    "eclarke": { ... }
  }
}

雖然資料庫使用 JSON 樹狀結構,但儲存在資料庫中的資料 會以特定原生類型表示,對應可用的 JSON 類型 協助您編寫更易於維護的程式碼

資料結構的最佳做法

避免建立巢狀資料

由於 Firebase 即時資料庫允許多達 32 層的巢狀資料建立巢狀結構, 您可能會想以此為預設結構。 不過,從資料庫內的某個位置擷取資料時,您也會擷取 所有子節點此外,如果您授予他人讀取或寫入權限 也會授予資料庫內所有資料的存取權 節點。因此,在實務上,最好將資料結構保持扁平 。

以下舉例說明巢狀資料品質不佳的原因, 多重巢狀結構:

{
  // This is a poorly nested data architecture, because iterating the children
  // of the "chats" node to get a list of conversation titles requires
  // potentially downloading hundreds of megabytes of messages
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "messages": {
        "m1": { "sender": "ghopper", "message": "Relay malfunction found. Cause: moth." },
        "m2": { ... },
        // a very long list of messages
      }
    },
    "two": { ... }
  }
}

使用這種巢狀設計,疊代資料就會造成問題。適用對象 例如,列出即時通訊對話的標題需要整個 chats 內容,包括所有成員與訊息。

壓平合併資料結構

如果資料是分割成獨立路徑 也稱為去正規化 如此就能有效率地下載,視需要在個別呼叫中下載。您可以考慮使用 這個簡化結構

{
  // Chats contains only meta info about each conversation
  // stored under the chats's unique ID
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": { ... },
    "three": { ... }
  },

  // Conversation members are easily accessible
  // and stored by chat conversation ID
  "members": {
    // we'll talk about indices like this below
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    },
    "two": { ... },
    "three": { ... }
  },

  // Messages are separate from data we may want to iterate quickly
  // but still easily paginated and queried, and organized by chat
  // conversation ID
  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      },
      "m2": { ... },
      "m3": { ... }
    },
    "two": { ... },
    "three": { ... }
  }
}

現在只要下載 每個對話的位元組數,可以快速擷取或顯示中繼資料 透過使用者介面建立聊天室使用者可以分別擷取訊息,並在收到郵件時顯示。 讓 UI 保持回應和快速

建立可大規模調整的資料

建構應用程式時,建議您下載部分清單。 這種情況尤其常見,因為這份清單含有數千筆記錄。 如果是靜態的單向關係, 子項物件

有時候這種關係比較多變,或者您可能得 並將這項資料去標準化。通常您可以使用查詢將資料去標準化 擷取部分資料,如 擷取資料

但這可能不夠。以雙向關係為例 方便使用者和群組使用者可以加入某個群組,而群組則是由 使用者清單當您決定要讓使用者加入哪些群組時 情況變得越來越複雜

需要能以流暢的方式列出使用者所屬的群組 只擷取這些群組的資料。群組索引有助於 最棒的是:

// An index to track Ada's memberships
{
  "users": {
    "alovelace": {
      "name": "Ada Lovelace",
      // Index Ada's groups in her profile
      "groups": {
         // the value here doesn't matter, just that the key exists
         "techpioneers": true,
         "womentechmakers": true
      }
    },
    ...
  },
  "groups": {
    "techpioneers": {
      "name": "Historical Tech Pioneers",
      "members": {
        "alovelace": true,
        "ghopper": true,
        "eclarke": true
      }
    },
    ...
  }
}

您可能會注意到,這麼做會儲存 分別位於 Ada 的記錄下方目前 alovelace 已在 和 techpioneers 已列在 Ada 的個人資料中。所以要刪除 Ada 就必須在兩個位置更新

這是雙向關係必要的備援功能。您可以 快速有效地擷取 Ada 成員,即使這些使用者或 組織擴充至數百萬個群組,或當即時資料庫安全性規則時 防止存取部分記錄。

這個方法會把 ID 列為鍵,並設定 值變成 true,所以檢查索引鍵就像讀取一樣簡單 請/users/$uid/groups/$group_id,並確認電子郵件地址是否為 null。建立索引的速度較快 比起查詢或掃描資料更有效率

後續步驟