Projektowanie schematów Data Connect

W przypadku Firebase Data Connect projektujesz schemat GraphQL, który reprezentuje model danych wymagany przez Twoją aplikację. Data Connect przekształca ten schemat w instancję Cloud SQL for PostgreSQL, która obsługuje Twoją aplikację. Następnie tworzysz zapytania i mutacje, aby komunikować się z backendem, i łączysz te operacje w konektory, aby używać danych z kodu klienta.

Data Connect udostępnia narzędzia AI, które pomagają projektować i wdrażać schematy. W tym przewodniku przedstawiamy ważne koncepcje projektowania schematów, które pomogą Ci w standardowych i wspomaganych przez AI przepływach pracy podczas tworzenia aplikacjipo jego zakończeniu.

W przewodniku dla początkujących przedstawiliśmy schemat aplikacji do oceniania filmów w PostgreSQL.

W tym przewodniku rozwijamy ten schemat i podajemy listę SQL odpowiadającą ostatecznemu schematowi aplikacji do recenzowania filmów.

Schemat aplikacji do recenzowania filmów

Załóżmy, że chcesz utworzyć usługę, która umożliwia użytkownikom przesyłanie i wyświetlanie recenzji filmów.

Aby obsługiwać podstawowe zapytania, musisz mieć początkowy schemat takiej aplikacji. Ten schemat możesz później rozszerzyć, aby tworzyć złożone zapytania relacyjne.

Data Connect zdefiniujesz typy GraphQL, aby określić kształt danych, o które klienci mogą wysyłać zapytania i którymi mogą manipulować. Podczas pisania schematu typy są tłumaczone na tabele Cloud SQL for PostgreSQL, najczęściej w bezpośredniej relacji między typami GraphQL a tabelami bazy danych, chociaż możliwe są też inne mapowania. W tym przewodniku znajdziesz przykłady od podstawowych po bardziej zaawansowane.

Zdefiniuj podstawowy typ Movie

Możesz zacząć od typu Movie.

Schemat pliku Movie zawiera podstawowe dyrektywy, takie jak:

  • @table(name)@col(name), aby dostosować nazwy tabel i kolumn SQL. Jeśli nie podasz nazwy, Data Connect wygeneruje nazwy w formacie snake_case.
  • @col(dataType), aby dostosować typy kolumn SQL.
  • @default, aby skonfigurować domyślne wartości kolumn SQL podczas wstawiania.

Więcej informacji znajdziesz w dokumentacji referencyjnej dotyczącej @table, @col@default.

# Movies
type Movie @table(name: "movie", key: "id") {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int
  genre: String @col(dataType: "varchar(20)")
  rating: Int
  description: String
}

Automatyczne przechowywanie ważnych danych użytkowników w User

Aplikacja będzie śledzić użytkowników, więc potrzebujesz typu User.

W tym przypadku szczególnie przydatna jest dyrektywa @default. Pole id może automatycznie pobierać identyfikator użytkownika z uwierzytelniania. Zwróć uwagę na użycie @default(expr: "auth.uid") w tym przykładzie.

# Users
# Suppose a user can leave reviews for movies
type User @table {
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
}

Kluczowe wartości skalarne i wartości serwera

Zanim przyjrzymy się bliżej aplikacji do oceniania filmów, warto zapoznać się z Data Connect kluczowymi skalaramiwartościami serwera.

Kluczowe skalary to zwięzłe identyfikatory obiektów, które Data Connect automatycznie tworzy na podstawie kluczowych pól w Twoich schematach. Kluczowe skalary dotyczą wydajności, ponieważ umożliwiają uzyskanie w ramach jednego wywołania informacji o tożsamości i strukturze danych. Są one szczególnie przydatne, gdy chcesz wykonywać sekwencyjne działania na nowych rekordach i potrzebujesz unikalnego identyfikatora do przekazywania do kolejnych operacji, a także gdy chcesz uzyskać dostęp do kluczy relacyjnych, aby wykonywać dodatkowe, bardziej złożone operacje.

Korzystając z wartości serwera, możesz skutecznie zezwolić serwerowi na dynamiczne wypełnianie pól w tabelach za pomocą przechowywanych lub łatwo obliczalnych wartości zgodnie z określonymi wyrażeniami CEL po stronie serwera w argumencie expr. Możesz na przykład zdefiniować pole z sygnaturą czasową, która jest stosowana, gdy uzyskuje się do niego dostęp przy użyciu czasu przechowywanego w żądaniu operacji, updatedAt: Timestamp! @default(expr: "request.time").

Obsługa relacji „wiele do wielu” w przypadku typów ActorMovieActor

Po obsłużeniu użytkowników możesz wrócić do modelowania danych o filmach.

Następnie chcesz, aby w Twoich filmach występowali aktorzy.

Tabela Actor jest dość prosta.

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID! @default(expr: "uuidV4()")
  name: String! @col(dataType: "varchar(30)")
}

Jeśli chcesz, aby aktorzy występowali w wielu filmach, a filmy miały wielu aktorów, musisz utworzyć „tabelę złączeń”.

Tabela MovieActor obsługuje relację wiele do wielu, a jej klucz podstawowy to kombinacja [movie, actor] (pola klucza obcego z tabel movie i actor).

# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary keys of this table
# In this case, the keys are [movieId, actorId], the foreign key fields of the reference fields [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  movie: Movie!
  # movieId: UUID! <- implicitly added foreign key field
  actor: Actor!
  # actorId: UUID! <- implicitly added foreign key field
  role: String! # "main" or "supporting"
  # optional other fields
}

Gdy zdefiniujesz relację SQL w tabeli z ograniczeniem klucza obcego, Data Connect automatycznie wygeneruje odpowiednie pole po drugiej stronie. Nie musisz definiować pola mapowania odwrotnego (np. z Actor z powrotem do MovieActor).

Obsługa relacji jeden do jednego w typie MovieMetadata

Teraz możesz śledzić reżyserów filmowych i skonfigurować relację jeden do jednegoMovie.

Aby dostosować ograniczenia klucza obcego, możesz użyć dyrektywy @ref:

  • @ref(fields) określa, których pól klucza obcego użyć.
  • @ref(references) określa pola, do których odwołuje się tabela docelowa (domyślnie jest to klucz podstawowy, ale działają też pola @unique). Jest to bardziej zaawansowana opcja. Data Connect często może to zrobić za Ciebie.

Więcej informacji znajdziesz w dokumentacji referencyjnej dotyczącej @ref.

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata @table {
  # @unique ensures that each Movie only has one MovieMetadata.
  movie: Movie! @unique
  # Since it references to another table type, it adds a foreign key constraint.
  #  movie: Movie! @unique @ref(fields: "movieId", references: "id")
  #  movieId: UUID! <- implicitly added foreign key field
  director: String
}

Używaj pól wygenerowanych na podstawie schematu do tworzenia operacji

Operacje Data Connect rozszerzą zestaw pól automatycznie wygenerowanych Data Connect na podstawie typów i relacji między typami w schemacie. Pola te są generowane przez narzędzia lokalne za każdym razem, gdy edytujesz schemat.

Załóżmy, że schemat zawiera typ Movie i powiązany z nim typ Actor. Data Connect generuje pola movie, movies, actors_on_movies i inne.

Zapytanie z polem
movie

Pole movie reprezentuje pojedynczy rekord w tabeli Movie.

Użyj tego pola, aby wysłać zapytanie o jeden film na podstawie jego klucza.

query GetMovie($myKey: Movie_Key!) {
  movie(key: $myKey) { title }
}

Zapytanie z polem
movies

Pole movies zawiera listę rekordów w tabeli Movie.

Użyj tego pola, aby wysłać zapytanie dotyczące wielu filmów, np. wszystkich filmów z danego roku.

query GetMovies($myYear: Int!) {
  movies(where: { year: { eq: $myYear } }) { title }
}

Zapytanie z polem
actors_on_movies

Pole actors_on_movies reprezentuje listę rekordów, które łączą tabele ActorMovie. Użyj tego pola, aby wysłać zapytanie o wszystkich aktorów powiązanych z danym filmem.

Użyj tego pola, aby wysłać zapytanie o wszystkich aktorów powiązanych z danym filmem.

  query GetActorsOnMovie($myKey: Movie_Key!) {
    actors_on_movies(where: { movie: { key: { eq: $myKey } } }) {
      actor { name }
    }
  }

przewodniku po implementacji zapytańprzewodniku po implementacji mutacji znajdziesz informacje o tym, jak implementować operacje za pomocą tych pól.

Bardziej zaawansowane koncepcje schematu

Aby wyjść poza podstawowe, ale przydatne typy i relacje, zapoznaj się z przykładami w dokumentacji.

Obsługiwane typy danych

Data Connect obsługuje te skalarne typy danych, które są przypisane do typów PostgreSQL za pomocą @col(dataType:).

Data Connect type Wbudowany typ GraphQL lub
Data Connect typ niestandardowy
Domyślny typ PostgreSQL Obsługiwane typy PostgreSQL
(alias w nawiasach)
Ciąg znaków GraphQL tekst text
bit(n), varbit(n)
char(n), varchar(n)
Liczba całkowita GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Liczba zmiennoprzecinkowa GraphQL float8 float4 (real)
float8 (double precision)
numeric (decimal)
Wartość logiczna GraphQL Wartość logiczna Wartość logiczna
UUID Niestandardowy uuid uuid
Int64 Niestandardowy bigint int8 (bigint, bigserial)
numeric (decimal)
Data Niestandardowy date data
Sygnatura czasowa Niestandardowy timestamptz

timestamptz

Uwaga: informacje o lokalnej strefie czasowej nie są przechowywane.
PostgreSQL konwertuje i przechowuje takie sygnatury czasowe w formacie UTC.

Wektor Niestandardowy vector

wektor

Zobacz Przeprowadzanie wyszukiwania podobieństwa wektorowego za pomocą Vertex AI.

  • GraphQL List jest mapowany na tablicę jednowymiarową.
    • Na przykład [Int] jest mapowany na int5[], a [Any] na jsonb[].
    • Data Connect nie obsługuje zagnieżdżonych tablic.

Odpowiednik w schemacie SQL

-- Movies Table
CREATE TABLE Movies (
    movie_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INT,
    genre VARCHAR(30),
    rating INT,
    description TEXT,
    tags TEXT[]
);
-- Movie Metadata Table
CREATE TABLE MovieMetadata (
    movie_id UUID REFERENCES Movies(movie_id) UNIQUE,
    director VARCHAR(255) NOT NULL,
    PRIMARY KEY (movie_id)
);
-- Actors Table
CREATE TABLE Actors (
    actor_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    name VARCHAR(30) NOT NULL
);
-- MovieActor Join Table for Many-to-Many Relationship
CREATE TABLE MovieActor (
    movie_id UUID REFERENCES Movies(movie_id),
    actor_id UUID REFERENCES Actors(actor_id),
    role VARCHAR(50) NOT NULL, # "main" or "supporting"
    PRIMARY KEY (movie_id, actor_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id),
    FOREIGN KEY (actor_id) REFERENCES Actors(actor_id)
);
-- Users Table
CREATE TABLE Users (
    user_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_auth VARCHAR(255) NOT NULL
    username VARCHAR(30) NOT NULL
);
-- Reviews Table
CREATE TABLE Reviews (
    review_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_id UUID REFERENCES Users(user_id),
    movie_id UUID REFERENCES Movies(movie_id),
    rating INT,
    review_text TEXT,
    review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (movie_id, user_id)
    FOREIGN KEY (user_id) REFERENCES Users(user_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
-- Self Join Example for Movie Sequel Relationship
ALTER TABLE Movies
ADD COLUMN sequel_to UUID REFERENCES Movies(movie_id);

Dalsze kroki

Może Cię zainteresować: