Cómo diseñar esquemas de Data Connect

Con Firebase Data Connect, diseñas un esquema de GraphQL que representa el modelo de datos requerido para tu aplicación. Data Connect convierte este esquema en la instancia de Cloud SQL para PostgreSQL que respalda tu app. Luego, creas consultas y mutaciones para interactuar con el backend y agrupar estas operaciones en conectores para usar tus datos desde el código del cliente.

Data Connect ofrece herramientas de IA para ayudarte a diseñar e implementar tus esquemas. En esta guía, se presentan conceptos importantes del diseño de esquemas para complementar y respaldar tus flujos de trabajo estándar y asistidos por IA cuando comiences a desarrollar una app y más allá.

En la guía de inicio, se presentó un esquema de app de revisión de películas para PostgreSQL.

En esta guía, se desarrolla aún más ese esquema y se proporciona un listado de SQL equivalente al esquema final de la app de reseñas de películas.

El esquema de una app de opiniones sobre películas

Imagina que quieres crear un servicio que permita a los usuarios enviar y ver reseñas de películas.

Necesitas un esquema inicial para que la app admita consultas básicas. Extenderás este esquema más adelante para crear consultas relacionales complejas.

En Data Connect, definirás tipos de GraphQL para definir la forma de los datos que tus clientes pueden consultar y manipular. Cuando escribes tu esquema, tus tipos se traducen a tablas de Cloud SQL para PostgreSQL, la mayoría de las veces en una relación directa entre los tipos de GraphQL y las tablas de la base de datos, aunque son posibles otras asignaciones. En esta guía, se muestran algunos ejemplos, desde los más básicos hasta los más avanzados.

Cómo definir un tipo Movie básico

Puedes comenzar con un tipo de Movie.

El esquema de Movie contiene directivas principales, como las siguientes:

  • @table(name) y @col(name) para personalizar los nombres de las tablas y las columnas de SQL Data Connect genera nombres en formato snake_case si no se especifican.
  • @col(dataType) para personalizar los tipos de columnas de SQL
  • @default para configurar los valores predeterminados de las columnas de SQL durante la inserción.

Para obtener más detalles, consulta los documentos de referencia de @table, @col y @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
}

Almacena automáticamente datos importantes del usuario en un tipo User

Tu app hará un seguimiento de los usuarios, por lo que necesitas un tipo User.

La directiva @default es especialmente útil en este caso. El campo id aquí puede tomar automáticamente el ID del usuario de la autenticación: observa el uso de @default(expr: "auth.uid") en el siguiente ejemplo.

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

Escalares de claves y valores del servidor

Antes de analizar más la app de reseñas de películas, es importante presentar los escalares clave y los valores del servidor de Data Connect.

Los escalares clave son identificadores de objetos concisos que Data Connect ensambla automáticamente a partir de los campos clave de tus esquemas. Los escalares clave se relacionan con la eficiencia, ya que te permiten encontrar en una sola llamada información sobre la identidad y la estructura de tus datos. Son especialmente útiles cuando deseas realizar acciones secuenciales en registros nuevos y necesitas un identificador único para pasar a las próximas operaciones, y también cuando deseas acceder a claves relacionales para realizar operaciones adicionales más complejas.

Con los valores del servidor, puedes permitir que el servidor complete de forma dinámica los campos de tus tablas con valores almacenados o que se pueden calcular fácilmente según expresiones CEL particulares del servidor en el argumento expr. Por ejemplo, puedes definir un campo con una marca de tiempo aplicada cuando se accede al campo con la hora almacenada en una solicitud de operación, updatedAt: Timestamp! @default(expr: "request.time").

Cómo controlar relaciones de varios a varios en tipos Actor y MovieActor

Con los usuarios controlados, puedes volver a modelar los datos de películas.

Luego, querrás que los actores protagonicen tus películas.

La tabla Actor es bastante sencilla.

# 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 quieres que los actores participen en varias películas y que las películas tengan varios actores, necesitarás una "tabla de unión".

La tabla MovieActor controla la relación de varios a varios, y su clave primaria es una combinación de [movie, actor] (los campos de clave externa de movie y 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
}

Cuando defines una relación de SQL en la tabla con una restricción de clave externa, Data Connect genera automáticamente el campo correspondiente en el otro lado. No es necesario que definas el campo de asignación inversa (p.ej., de Actor a MovieActor).

Cómo controlar relaciones de uno a uno en un tipo MovieMetadata

Ahora, haz un seguimiento de los directores de películas y configura una relación uno a uno con Movie.

Puedes usar la directiva @ref para personalizar las restricciones de clave externa:

  • @ref(fields) especifica qué campos de clave externa se deben usar.
  • @ref(references) especifica los campos a los que se hace referencia en la tabla de destino (de forma predeterminada, la clave primaria, pero los campos @unique también funcionan). Esta es una opción más avanzada; Data Connect a menudo puede inferir esto por ti.

Para obtener más detalles, consulta los documentos de referencia de @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
}

Usa los campos generados a partir de tu esquema para crear operaciones

Tus operaciones de Data Connect extenderán un conjunto de campos Data Connect generados automáticamente según los tipos y las relaciones de tipos en tu esquema. Estos campos se generan con herramientas locales cada vez que editas tu esquema.

Supongamos que tu esquema contiene un tipo Movie y un tipo Actor asociado. Data Connect genera los campos movie, movies y actors_on_movies, entre otros.

Consulta con el campo
movie

El campo movie representa un solo registro en la tabla Movie.

Usa este campo para consultar una sola película por su clave.

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

Consulta con el campo
movies

El campo movies representa una lista de registros en la tabla Movie.

Usa este campo para consultar varias películas, por ejemplo, todas las películas de un año determinado.

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

Consulta con el campo
actors_on_movies

El campo actors_on_movies representa una lista de registros que conectan las tablas Actor y Movie. Usa este campo para consultar todos los actores asociados con una película determinada.

Usa este campo para consultar todos los actores asociados con una película determinada.

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

Teniendo esto en cuenta, puedes leer cómo implementar operaciones con estos campos en la guía para implementar consultas y la guía para implementar mutaciones.

Conceptos de esquema más avanzados

Para ir más allá de los tipos y las relaciones básicos, pero útiles, consulta los ejemplos en la documentación de referencia.

Tipos de datos admitidos

Data Connect admite los siguientes tipos de datos escalares, con asignaciones a tipos de PostgreSQL a través de @col(dataType:).

Data Connect type Tipo integrado de GraphQL o tipo personalizado
Data Connect
Tipo de PostgreSQL predeterminado Tipos de PostgreSQL admitidos
(alias entre paréntesis)
String GraphQL texto text
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Número de punto flotante GraphQL float8 float4 (real)
float8 (doble precisión)
numeric (decimal)
Booleano GraphQL booleano booleano
UUID Personalizado uuid uuid
Int64 Personalizado bigint int8 (bigint, bigserial)
numeric (decimal)
Fecha Personalizado date fecha
Marca de tiempo Personalizado timestamptz

timestamptz

Nota: No se almacena información sobre la zona horaria local.
PostgreSQL convierte y almacena esas marcas de tiempo como UTC.

Vector Personalizado vector

vector

Consulta Cómo realizar una búsqueda de similitud de vectores con Vertex AI.

  • El List de GraphQL se asigna a un array unidimensional.
    • Por ejemplo, [Int] se asigna a int5[] y [Any] se asigna a jsonb[].
    • Data Connect no admite arrays anidados.

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

Próximos pasos

También te puede interesar: