Progettare gli schemi di Data Connect

Con Firebase Data Connect, progetti uno schema GraphQL che rappresenta il modello di dati richiesto per la tua applicazione. Data Connect converte questo schema nell'istanza Cloud SQL per PostgreSQL che supporta la tua app. Poi crei query e mutazioni per interfacciarti con il backend e raggruppi queste operazioni in connettori per utilizzare i dati dal codice client.

Data Connect offre strumenti di AI per aiutarti a progettare e implementare gli schemi. Questa guida introduce concetti importanti di progettazione dello schema per supportare e integrare i tuoi workflow standard e assistiti dall'AI quando inizi a sviluppare un'app e oltre.

La Guida introduttiva ha introdotto uno schema di app di recensioni di film per PostgreSQL.

Questa guida sviluppa ulteriormente lo schema e fornisce un elenco SQL equivalente allo schema finale dell'app di recensioni di film.

Lo schema per un'app di recensioni di film

Immagina di voler creare un servizio che consenta agli utenti di inviare e visualizzare recensioni di film.

Per supportare le query di base, devi disporre di uno schema iniziale per l'app. In seguito estenderai questo schema per creare query relazionali complesse.

In Data Connect, definirai i tipi GraphQL per definire la forma dei dati che i tuoi client possono interrogare e manipolare. Quando scrivi lo schema, i tipi vengono tradotti in tabelle Cloud SQL per PostgreSQL, il più delle volte in una relazione diretta tra i tipi GraphQL e le tabelle del database, anche se sono possibili altre mappature. Questa guida mostra alcuni esempi di base e più avanzati.

Definisci un tipo Movie di base

Puoi iniziare con un tipo di Movie.

Lo schema per Movie contiene direttive di base come:

  • @table(name) e @col(name) per personalizzare i nomi di tabelle e colonne SQL. Se non specificati, Data Connect genera nomi in formato snake_case.
  • @col(dataType) per personalizzare i tipi di colonne SQL.
  • @default per configurare i valori predefiniti delle colonne SQL durante l'inserimento.

Per ulteriori dettagli, consulta la documentazione di riferimento per @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
}

Archivia automaticamente i dati utente importanti in un tipo User

La tua app monitorerà gli utenti, quindi hai bisogno di un tipo User.

La direttiva @default è particolarmente utile in questo caso. Il campo id qui può recuperare automaticamente l'ID utente dall'autenticazione: nota l'utilizzo di @default(expr: "auth.uid") nell'esempio seguente.

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

Scalari chiave e valori del server

Prima di esaminare più da vicino l'app di recensioni di film, è importante introdurre gli Data Connect scalari chiave e i valori del server.

Gli scalari chiave sono identificatori di oggetti concisi che Data Connect vengono assemblati automaticamente dai campi chiave negli schemi. Gli scalari chiave riguardano l'efficienza, in quanto ti consentono di trovare in una singola chiamata informazioni sull'identità e sulla struttura dei tuoi dati. Sono particolarmente utili quando vuoi eseguire azioni sequenziali sui nuovi record e hai bisogno di un identificatore univoco da passare alle operazioni imminenti, nonché quando vuoi accedere alle chiavi relazionali per eseguire operazioni aggiuntive più complesse.

Utilizzando i valori del server, puoi consentire al server di compilare dinamicamente i campi delle tabelle utilizzando valori archiviati o facilmente calcolabili in base a particolari espressioni CEL lato server nell'argomento expr. Ad esempio, puoi definire un campo con un timestamp applicato quando si accede al campo utilizzando l'ora memorizzata in una richiesta di operazione, updatedAt: Timestamp! @default(expr: "request.time").

Gestire le relazioni molti-a-molti nei tipi Actor e MovieActor

Ora che hai gestito gli utenti, puoi tornare alla modellazione dei dati dei film.

Poi, vuoi che gli attori recitino nei tuoi film.

La tabella Actor è piuttosto semplice.

# 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)")
}

Se vuoi che gli attori partecipino a più film e che i film abbiano più attori, ti servirà una "tabella di unione".

La tabella MovieActor gestisce la relazione molti-a-molti e la sua chiave primaria è una combinazione di [movie, actor] (i campi di chiave esterna di movie e 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
}

Quando definisci una relazione SQL nella tabella con un vincolo di chiave esterna, Data Connect genera automaticamente il campo corrispondente sull'altro lato. Non è necessario definire il campo di mapping inverso (ad es. da Actor a MovieActor).

Gestire le relazioni one-to-one in un tipo MovieMetadata

Ora puoi monitorare i registi dei film e configurare una relazione uno a uno con Movie.

Puoi utilizzare la direttiva @ref per personalizzare i vincoli di chiave esterna:

  • @ref(fields) specifica quali campi di chiave esterna utilizzare.
  • @ref(references) specifica i campi a cui viene fatto riferimento nella tabella di destinazione (il valore predefinito è la chiave primaria, ma funzionano anche i campi @unique). Questa è un'opzione più avanzata; Data Connect spesso può dedurlo per te.

Per ulteriori dettagli, consulta la documentazione di riferimento per @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
}

Utilizzare i campi generati dallo schema per creare operazioni

Le operazioni Data Connect estenderanno un insieme di campi generati automaticamente Data Connect in base ai tipi e alle relazioni tra i tipi nello schema. Questi campi vengono generati dagli strumenti locali ogni volta che modifichi lo schema.

Supponiamo che lo schema contenga un tipo Movie e un tipo Actor associato. Data Connect genera i campi movie, movies, actors_on_movies e altri ancora.

Query con il campo
movie

Il campo movie rappresenta un singolo record nella tabella Movie.

Utilizza questo campo per eseguire query su un singolo film in base alla relativa chiave.

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

Query con il campo
movies

Il campo movies rappresenta un elenco di record nella tabella Movie.

Utilizza questo campo per eseguire query su più film, ad esempio tutti i film di un determinato anno.

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

Query con il campo
actors_on_movies

Il campo actors_on_movies rappresenta un elenco di record che collegano le tabelle Actor e Movie. Utilizza questo campo per eseguire query su tutti gli attori associati a un determinato film.

Utilizza questo campo per eseguire query su tutti gli attori associati a un determinato film.

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

Tenendo presente questo, puoi leggere come implementare le operazioni utilizzando questi campi nella guida all'implementazione delle query e nella guida all'implementazione delle mutazioni.

Concetti più avanzati dello schema

Per andare oltre i tipi e le relazioni di base ma utili, consulta gli esempi nella documentazione di riferimento.

Tipi di dati supportati

Data Connect supporta i seguenti tipi di dati scalari, con assegnazioni ai tipi PostgreSQL utilizzando @col(dataType:).

Data Connect type Tipo incorporato GraphQL o
tipo personalizzatoData Connect
Tipo PostgreSQL predefinito Tipi PostgreSQL supportati
(alias tra parentesi)
Stringa GraphQL testo text
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
In virgola mobile GraphQL float8 float4 (real)
float8 (double precision)
numeric (decimal)
Booleano GraphQL booleano booleano
UUID Personalizzato uuid uuid
Int64 Personalizzato bigint int8 (bigint, bigserial)
numeric (decimal)
Data Personalizzato date data
Timestamp Personalizzato timestamptz

timestamptz

Nota:le informazioni sul fuso orario locale non vengono memorizzate.
PostgreSQL converte e archivia questi timestamp in formato UTC.

Vettoriale Personalizzato vector

vettore

Consulta Eseguire la ricerca di similarità vettoriale con Vertex AI.

  • GraphQL List viene mappato a un array unidimensionale.
    • Ad esempio, [Int] corrisponde a int5[], [Any] corrisponde a jsonb[].
    • Data Connect non supporta gli array nidificati.

Schema SQL equivalente

-- 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);

Passaggi successivi

Potrebbe interessarti: