Concevoir des schémas Data Connect

Avec Firebase Data Connect, vous concevez un schéma GraphQL qui représente le modèle de données requis pour votre application. Data Connect convertit ce schéma en instance Cloud SQL pour PostgreSQL qui soutient votre application. Vous créez ensuite des requêtes et des mutations pour interagir avec le backend, et regroupez ces opérations dans des connecteurs pour utiliser vos données à partir du code client.

Data Connect propose des outils d'IA pour vous aider à concevoir et à implémenter vos schémas. Ce guide présente des concepts importants de conception de schéma pour prendre en charge et compléter vos workflows standards et assistés par l'IA lorsque vous commencez à développer une application et au-delà.

Le guide de démarrage a présenté un schéma d'application d'avis sur des films pour PostgreSQL.

Ce guide développe davantage ce schéma et fournit une liste SQL équivalente au schéma final de l'application d'avis sur les films.

Schéma d'une application d'avis sur des films

Imaginons que vous souhaitiez créer un service permettant aux utilisateurs d'envoyer et de consulter des critiques de films.

Vous avez besoin d'un schéma initial pour qu'une telle application puisse prendre en charge les requêtes de base. Vous étendrez ce schéma ultérieurement pour créer des requêtes relationnelles complexes.

Dans Data Connect, vous définirez des types GraphQL pour définir la forme des données que vos clients peuvent interroger et manipuler. Lorsque vous écrivez votre schéma, vos types sont traduits en tables Cloud SQL pour PostgreSQL, le plus souvent dans une relation directe entre les types GraphQL et les tables de base de données, bien que d'autres mappages soient possibles. Ce guide présente quelques exemples, du plus simple au plus avancé.

Définir un type Movie de base

Vous pouvez commencer par un type Movie.

Le schéma de Movie contient des directives de base telles que :

  • @table(name) et @col(name) pour personnaliser les noms de table et de colonne SQL. Si aucun nom n'est spécifié, Data Connect génère des noms snake_case.
  • @col(dataType) pour personnaliser les types de colonnes SQL.
  • @default pour configurer les valeurs par défaut des colonnes SQL lors de l'insertion.

Pour en savoir plus, consultez la documentation de référence sur @table, @col et @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
}

Stocker automatiquement les données utilisateur importantes dans un type User

Votre application suivra les utilisateurs. Vous avez donc besoin d'un type User.

L'instruction @default est particulièrement utile dans ce cas. Le champ id peut récupérer automatiquement l'ID de l'utilisateur à partir de l'authentification. Notez l'utilisation de @default(expr: "auth.uid") dans l'exemple suivant.

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

Valeurs clés et valeurs du serveur

Avant d'examiner plus en détail l'application d'avis sur les films, il est important de présenter les scalaires clés et les valeurs de serveur de Data Connect.

Les scalaires clés sont des identifiants d'objet concis que Data Connect assemble automatiquement à partir des champs clés de vos schémas. Les scalaires clés concernent l'efficacité. Ils vous permettent de trouver en un seul appel des informations sur l'identité et la structure de vos données. Ils sont particulièrement utiles lorsque vous souhaitez effectuer des actions séquentielles sur de nouveaux enregistrements et que vous avez besoin d'un identifiant unique à transmettre aux opérations à venir. Ils le sont également lorsque vous souhaitez accéder à des clés relationnelles pour effectuer des opérations supplémentaires plus complexes.

En utilisant les valeurs de serveur, vous pouvez laisser le serveur remplir dynamiquement les champs de vos tableaux à l'aide de valeurs stockées ou facilement calculables, selon des expressions CEL côté serveur spécifiques dans l'argument expr. Par exemple, vous pouvez définir un champ avec un code temporel appliqué lorsque le champ est consulté à l'aide de l'heure stockée dans une requête d'opération, updatedAt: Timestamp! @default(expr: "request.time").

Gérer les relations plusieurs à plusieurs dans les types Actor et MovieActor

Maintenant que vous avez géré les utilisateurs, vous pouvez revenir à la modélisation des données de films.

Ensuite, vous devez choisir les acteurs qui joueront dans vos films.

La table Actor est assez simple.

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

Si vous souhaitez que les acteurs figurent dans plusieurs films et que les films comportent plusieurs acteurs, vous aurez besoin d'une "table de jointure".

La table MovieActor gère la relation plusieurs-à-plusieurs. Sa clé primaire est une combinaison de [movie, actor] (les champs de clé étrangère de movie et 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
}

Lorsque vous définissez une relation SQL sur la table avec une contrainte de clé étrangère, Data Connect génère automatiquement le champ correspondant de l'autre côté. Vous n'avez pas besoin de définir le champ de mappage inverse (par exemple, de Actor à MovieActor).

Gérer les relations un-à-un dans un type MovieMetadata

Maintenant, suivez les réalisateurs de films et configurez une relation un-à-un avec Movie.

Vous pouvez utiliser la directive @ref pour personnaliser les contraintes de clé étrangère :

  • @ref(fields) spécifie les champs de clé étrangère à utiliser.
  • @ref(references) spécifie les champs référencés dans la table cible (par défaut, il s'agit de la clé primaire, mais les champs @unique fonctionnent également). Il s'agit d'une option plus avancée. Data Connect peut souvent l'inférer pour vous.

Pour en savoir plus, consultez la documentation de référence sur @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
}

Utiliser les champs générés à partir de votre schéma pour créer des opérations

Vos opérations Data Connect étendront un ensemble de champs Data Connect générés automatiquement en fonction des types et des relations de type dans votre schéma. Ces champs sont générés par des outils locaux chaque fois que vous modifiez votre schéma.

Supposons que votre schéma contienne un type Movie et un type Actor associé. Data Connect génère les champs movie, movies, actors_on_movies et plus encore.

Requête avec le champ
movie

Le champ movie représente un seul enregistrement dans la table Movie.

Utilisez ce champ pour interroger un seul film à l'aide de sa clé.

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

Requête avec le champ
movies

Le champ movies représente une liste d'enregistrements dans la table Movie.

Utilisez ce champ pour interroger plusieurs films, par exemple tous les films d'une année donnée.

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

Requête avec le champ
actors_on_movies

Le champ actors_on_movies représente une liste d'enregistrements qui relient les tables Actor et Movie. Utilisez ce champ pour interroger tous les acteurs associés à un film donné.

Utilisez ce champ pour interroger tous les acteurs associés à un film donné.

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

Dans cette optique, vous pouvez lire comment implémenter des opérations à l'aide de ces champs dans le guide d'implémentation des requêtes et le guide d'implémentation des mutations.

Concepts de schéma plus avancés

Pour aller au-delà des types et des relations de base, mais utiles, consultez les exemples de la documentation de référence.

Types de données acceptés

Data Connect est compatible avec les types de données scalaires suivants, avec des affectations aux types PostgreSQL à l'aide de @col(dataType:).

Data Connect type Type intégré GraphQL ou type personnalisé
Data Connect
Type PostgreSQL par défaut Types PostgreSQL compatibles
(alias entre parenthèses)
Chaîne GraphQL texte text
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Float GraphQL float8 float4 (réel)
float8 (double précision)
numeric (décimal)
Booléen GraphQL booléen booléen
UUID Personnalisé uuid uuid
Int64 Personnalisé bigint int8 (bigint, bigserial)
numeric (decimal)
Date Personnalisé date date
Horodatage Personnalisé timestamptz

timestamptz

Remarque : Les informations sur le fuseau horaire local ne sont pas stockées.
PostgreSQL convertit et stocke ces codes temporels au format UTC.

Vecteur Personnalisé vecteur

vecteur

Consultez Effectuer une recherche de similarité vectorielle avec Vertex AI.

  • GraphQL List correspond à un tableau unidimensionnel.
    • Par exemple, [Int] correspond à int5[] et [Any] correspond à jsonb[].
    • Data Connect n'est pas compatible avec les tableaux imbriqués.

Schéma SQL équivalent

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

Étapes suivantes

Vous pourriez être intéressé par :