Tworzenie struktury bazy danych

Ten przewodnik zawiera niektóre kluczowe koncepcje architektury danych oraz najlepsze praktyki dotyczące strukturyzowania danych JSON w Twoim pliku Firebase Realtime Database.

Stworzenie prawidłowo zorganizowanej bazy danych wymaga dużej precyzji. Przede wszystkim musisz zaplanować sposób zapisywania danych. pobrać później, aby maksymalnie uprościć ten proces.

Sposób uporządkowania danych: drzewo JSON

Wszystkie dane Firebase Realtime Database są przechowywane jako obiekty JSON. Pomyśl o tym, jako drzewo JSON hostowane w chmurze. W przeciwieństwie do bazy danych SQL tabeli lub rekordów. Po dodaniu danych do drzewa JSON staje się on węzłem istniejącą strukturę JSON z powiązanym kluczem. Możesz dostarczyć własne klucze, takich jak identyfikatory użytkowników lub nazwy semantyczne. Można też je podać za pomocą funkcji metodę push().

Jeśli tworzysz własne klucze, muszą być one zakodowane w formacie UTF-8, a maksymalna może mieć 768 bajtów i nie może zawierać elementów sterujących ., $, #, [, ], / ani ASCII. 0–31 lub 127. W wartościach nie można używać znaków sterujących ASCII lub sami.

Weźmy na przykład aplikację czatu, która pozwala użytkownikom przechowywać profil i listę kontaktów. Typowy profil użytkownika znajduje się na ścieżce, takiej jak /users/$uid Użytkownik alovelace może mieć wpis bazy danych, który wygląda mniej więcej tak:

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

Chociaż baza danych korzysta z drzewa JSON, dane przechowywane w bazie danych można reprezentowane jako określone typy natywne, które odpowiadają dostępnym typom JSON aby łatwiej było pisać kod łatwiejszy w utrzymaniu.

Sprawdzone metody tworzenia struktury danych

Unikaj zagnieżdżania danych

Funkcja Firebase Realtime Database umożliwia zagnieżdżanie danych do 32 poziomów, może wydawać się, że powinna to być struktura domyślna. Jednak podczas pobierania danych z lokalizacji w bazie danych pobierasz również wszystkich jego węzłów podrzędnych. Ponadto, gdy przyznasz komuś uprawnienia do odczytu lub zapisu w węźle swojej bazy danych, udzielasz mu dostępu do wszystkich danych do węzła. Dlatego w praktyce najlepiej jest zadbać o płaską strukturę danych. jak to tylko możliwe.

Oto przykład tego, dlaczego dane zagnieżdżone są niewłaściwe: struktura wielozagnieżdżona:

{
  // 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": { ... }
  }
}

Taki zagnieżdżony układ sprawia, że powtarzanie danych staje się problematyczne. Dla: Na przykład wystawienie tytułów rozmów na czacie wymaga umieszczenia całego atrybutu chats drzewo zawierające wszystkich użytkowników i wiadomości, które ma zostać pobrane do klienta.

Spłaszcz struktury danych

Jeśli dane zostaną podzielone na oddzielne ścieżki, czyli denormalizacja, można go wydajnie pobierać w ramach osobnych wywołań. Rozważ tę spłaszczoną strukturę:

{
  // 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": { ... }
  }
}

Obecnie można iterować listę pokojów, pobierając tylko można szybko pobrać metadane na potrzeby wykazu, i pokojami w interfejsie. Wiadomości można pobierać osobno i wyświetlać w miarę ich odbierania. co sprawia, że interfejs jest szybki i elastyczny.

Tworzenie skalujących danych

Podczas tworzenia aplikacji często lepiej jest pobrać podzbiór listy. Zdarza się to szczególnie wtedy, gdy lista zawiera tysiące rekordów. Jeśli ta zależność jest statyczna i jednokierunkowa, możesz po prostu zagnieździć obiektów potomnych znajdujących się pod obiektem nadrzędnym.

Czasami ta relacja jest bardziej dynamiczna lub konieczne może być denormalizować te dane. Dane można zdenormalizować dane za pomocą zapytania. podzbioru danych, co zostało omówione w Odzyskaj dane.

Jednak nawet to może nie być wystarczające. Rozważmy na przykład relację dwukierunkową między użytkownikami a grupami. Użytkownicy mogą należeć do określonej grupy, a grupy składają się z listy użytkowników. Gdy przychodzi czas na określenie, do których grup należy użytkownik, sprawy się komplikują.

Potrzebny jest elegancki sposób tworzenia listy grup, do których należy użytkownik, pobierać tylko dane dotyczące tych grup. Indeks grup może ułatwić znajdziesz tutaj:

// 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
      }
    },
    ...
  }
}

Możesz zauważyć, że część danych powstaje duplikat przez przechowywanie relacji zarówno w imieniu Ady, jak i pod grupą. Teraz strona alovelace jest zindeksowana w a techpioneers jest na liście w profilu Ady. Aby usunąć Adę, z grupy, należy zaktualizować go w dwóch miejscach.

Jest to konieczne nadmiarowość w przypadku relacji dwukierunkowych. Dzięki niemu możesz: aby szybko i skutecznie pobierać informacje o członkostwie Ady, nawet jeśli lista użytkowników grupy skalują się do milionów lub gdy Realtime Database reguły zabezpieczeń zablokować dostęp do niektórych rekordów.

Ta metoda polega na odwracaniu danych przez wyświetlanie identyfikatorów jako kluczy i ustawienie parametru ma wartość true (prawda), dzięki czemu sprawdzanie klucza jest tak proste, jak odczytywanie /users/$uid/groups/$group_id i sprawdzam, czy to null. Indeks jest szybszy i o wiele efektywniejsze niż wykonywanie zapytań czy skanowanie danych.

Następne kroki