Tworzenie struktury bazy danych

Zanim zaczniesz

Zanim będzie można użyć Realtime Database, musisz:

  • Zarejestruj projekt Unity i skonfiguruj go tak, aby używał Firebase.

    • Jeśli Twój projekt w Unity korzysta już z Firebase, jest już zarejestrowany i skonfigurowany pod kątem tej usługi.

    • Jeśli nie masz projektu Unity, możesz pobrać próbną aplikację.

  • Dodaj pakiet SDK Firebase Unity (w szczególności FirebaseDatabase.unitypackage) do w Twoim projekcie Unity.

.

Pamiętaj, że dodanie Firebase do projektu Unity wymaga wykonania zadań zarówno w konsoli Firebase, jak i w otwartym projekcie Unity (np. pobieranie plików konfiguracji Firebase z konsoli i przenoszenie ich do projektu Unity).

Strukturyzowanie danych

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

Tworzenie odpowiednio uporządkowanej bazy danych wymaga sporo przemyślenia. 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. Gdy dodasz dane do drzewa JSON, staną się one węzłem w dotychczasowej strukturze JSON z powiązanym kluczem. Możesz podać własne klucze, takie jak identyfikatory użytkowników lub nazwy semantyczne, albo możesz je otrzymać za pomocą metody 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ę do czatu, która umożliwia użytkownikom przechowywanie podstawowego profilu i listy kontaktów. Typowy profil użytkownika znajduje się na ścieżce takiej jak /users/$uid. Użytkownik alovelace może mieć w bazie danych wpis o takiej treści:

{
  "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

Ponieważ Firebase Realtime Database umożliwia zagnieżdżanie danych na 32 poziomach, możesz pomyśleć, że to powinna być domyślna struktura. Jednak podczas pobierania danych z lokalizacji w bazie danych pobierasz również wszystkich jego węzłów podrzędnych. Ponadto, gdy przyznasz komuś dostęp do odczytu lub zapisu w węźle w bazie danych, przyznasz mu też dostęp do wszystkich danych w tym węźle. Dlatego w praktyce najlepiej jest, aby struktura danych była jak najbardziej płaska.

Przykład struktury wielokrotnie zagnieżdżonej, która pokazuje, dlaczego dane zagnieżdżone są złe:

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

W przypadku takiej zagnieżchłej struktury przechodzenie przez dane staje się problematyczne. Na przykład wyświetlanie tytułów rozmów na czacie wymaga pobrania na klienta całego drzewa chats, w tym wszystkich uczestników i wiadomości.

Spłaszcz struktury danych

Jeśli dane są podzielone na osobne ścieżki (tzw. denormalizacja), można je efektywnie pobierać w osobnych wywołaniach. 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": { ... }
  }
}

Teraz można przejść przez listę pokoi, pobierając tylko kilka bajtów na rozmowę, szybko pobierając metadane do wyświetlania listy lub wyświetlania pokoi w interfejsie. Wiadomości można pobierać osobno i wyświetlać w miarę ich przychodzenia, dzięki czemu interfejs pozostaje responsywny i szybki.

Tworzenie skalujących danych

Podczas tworzenia aplikacji często lepiej jest pobrać podzbiór listy. Zdarza się to szczególnie często, gdy lista zawiera tysiące rekordów. Jeśli ta relacja jest statyczna i jednokierunkowa, możesz po prostu umieścić obiekty podrzędne pod obiektem nadrzędnym.

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

Ale nawet to może nie wystarczyć. 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 na wyświetlenie listy grup, do których należy użytkownik, oraz pobieranie danych tylko z tych grup. Indeks grup może bardzo pomóc:

// 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 niektóre dane są powielane, ponieważ relacja jest przechowywana zarówno w rekordzie Ada, jak i w grupie. Teraz alovelace jest indeksowany w ramach grupy, a techpioneers jest widoczny w profilu Ada. Aby usunąć Ada z grupy, trzeba zaktualizować tę informację w 2 miejscach.

Jest to niezbędna nadmiarowość w przypadku relacji dwukierunkowych. Umożliwia to szybkie i wydajne pobieranie członkostw Ada, nawet gdy lista użytkowników lub grup obejmuje miliony elementów lub gdy Realtime Database zasady bezpieczeństwa uniemożliwiają 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 znacznie wydajniejszy niż skanowanie lub wysyłanie zapytań do danych.

Następne kroki