Проектирование схем Data Connect

С помощью Firebase Data Connect вы разрабатываете схему GraphQL, которая представляет модель данных, необходимую для вашего приложения. Data Connect преобразует эту схему в экземпляр Cloud SQL для PostgreSQL, который поддерживает ваше приложение. Затем вы создаете запросы и мутации для взаимодействия с бэкэндом и объединяете эти операции в коннекторы для использования ваших данных из клиентского кода.

Data Connect предлагает инструменты ИИ, которые помогут вам разрабатывать и внедрять схемы. Это руководство знакомит с важными концепциями проектирования схем, которые поддерживают и дополняют ваши стандартные и поддерживаемые ИИ рабочие процессы, когда вы начинаете разрабатывать приложение и не только .

В руководстве по началу работы представлена ​​схема приложения для обзора фильмов для PostgreSQL.

В этом руководстве эта схема развивается дальше и приводится листинг SQL, эквивалентный окончательной схеме приложения для обзора фильмов.

Схема для приложения для обзора фильмов

Представьте, что вы хотите создать сервис, позволяющий пользователям отправлять и просматривать рецензии на фильмы.

Вам нужна начальная схема для такого приложения, чтобы поддерживать базовые запросы. Позже вы расширите эту схему для создания сложных реляционных запросов.

В Data Connect вы определите типы GraphQL , чтобы определить форму данных, которые ваши клиенты могут запрашивать и обрабатывать. Когда вы пишете свою схему, ваши типы транслируются в таблицы Cloud SQL для PostgreSQL, чаще всего в прямой связи между типами GraphQL и таблицами базы данных, хотя возможны и другие сопоставления. В этом руководстве приведены некоторые примеры от базовых до более продвинутых.

Определите базовый тип Movie

Вы можете начать с типа Movie .

Схема для Movie содержит основные директивы, такие как:

  • @table(name) и @col(name) для настройки имен таблиц и столбцов SQL. Data Connect генерирует имена в формате snake_case, если не указано иное.
  • @col(dataType) для настройки типов столбцов SQL.
  • @default для настройки значений столбцов SQL по умолчанию во время вставки.

Более подробную информацию можно найти в справочной документации по @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
}

Автоматически сохранять важные пользовательские данные в типе User

Ваше приложение будет отслеживать пользователей, поэтому вам нужен тип « User .

Директива @default особенно полезна в этом случае. Поле id здесь может автоматически извлекать идентификатор пользователя из аутентификации: обратите внимание на использование @default(expr: "auth.uid") в следующем примере.

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

Ключевые скаляры и серверные значения

Прежде чем подробнее рассмотреть приложение для обзора фильмов, важно познакомить вас с ключевыми скалярами и значениями сервера Data Connect .

Ключевые скаляры — это краткие идентификаторы объектов, которые Data Connect автоматически собирает из ключевых полей в ваших схемах. Ключевые скаляры — это эффективность, позволяющая вам находить в одном вызове информацию об идентичности и структуре ваших данных. Они особенно полезны, когда вы хотите выполнять последовательные действия с новыми записями и вам нужен уникальный идентификатор для передачи в предстоящие операции, а также когда вы хотите получить доступ к реляционным ключам для выполнения дополнительных более сложных операций.

Используя серверные значения , вы можете эффективно позволить серверу динамически заполнять поля в ваших таблицах, используя сохраненные или легко вычисляемые значения в соответствии с определенными серверными выражениями CEL в аргументе expr . Например, вы можете определить поле с временной меткой, применяемой при доступе к полю, используя время, сохраненное в запросе операции, updatedAt: Timestamp! @default(expr: "request.time") .

Обработка отношений «многие ко многим» в типах Actor и MovieActor

Разобравшись с пользователями, можно вернуться к моделированию данных фильмов.

Далее вы хотите, чтобы в ваших фильмах снимались актеры.

Таблица Actor довольно проста.

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

Если вы хотите, чтобы актеры снимались в нескольких фильмах, а в фильмах было несколько актеров, вам понадобится «таблица объединения».

Таблица MovieActor обрабатывает отношение «многие ко многим» , а ее первичным ключом является комбинация [movie, actor] (поля внешнего ключа из movie и 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
}

Когда вы определяете связь SQL в таблице с ограничением внешнего ключа, Data Connect автоматически генерирует соответствующее поле на другой стороне. Вам не нужно определять поле обратного сопоставления (например, из Actor обратно в MovieActor ).

Обработка отношений «один к одному» в типе MovieMetadata

Теперь следите за режиссерами фильмов, а также наладьте индивидуальную связь с Movie .

Для настройки ограничений внешнего ключа можно использовать директиву @ref :

  • @ref(fields) указывает, какие поля внешнего ключа следует использовать.
  • @ref(references) указывает поля, на которые ссылаются в целевой таблице (по умолчанию это первичный ключ, но поля @unique тоже работают). Это более продвинутый вариант; Data Connect часто может вывести это для вас.

Более подробную информацию можно найти в справочной документации по @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
}

Используйте поля, созданные на основе вашей схемы, для построения операций.

Ваши операции Data Connect расширят набор полей, автоматически сгенерированных Data Connect на основе типов и отношений типов в вашей схеме. Эти поля генерируются локальными инструментами всякий раз, когда вы редактируете свою схему.

Предположим, что ваша схема содержит тип Movie и связанный с ним тип Actor . Data Connect генерирует поля movie , movies , actors_on_movies и многое другое.

Запрос с
поле movie

Поле movie представляет собой отдельную запись в таблице Movie .

Используйте это поле для запроса отдельного фильма по его ключу.

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

Запрос с
поле movies

Поле movies представляет собой список записей в таблице Movie .

Используйте это поле для запроса нескольких фильмов, например, всех фильмов определенного года.

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

Запрос с
поле actors_on_movies

Поле actors_on_movies представляет собой список записей, которые связывают таблицы Actor и Movie . Используйте это поле для запроса всех актеров, связанных с данным фильмом.

Используйте это поле для запроса всех актеров, связанных с данным фильмом.

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

Имея это в виду, вы можете прочитать о том, как реализовать операции с использованием этих полей в руководстве по реализации запросов и руководстве по реализации мутаций .

Более продвинутые концепции схем

Чтобы выйти за рамки базовых, но полезных типов и отношений, обратитесь к примерам в справочной документации .

Поддерживаемые типы данных

Data Connect поддерживает следующие скалярные типы данных с присвоением типам PostgreSQL с помощью @col(dataType:) .

Тип Data Connect Встроенный тип GraphQL или
Пользовательский тип Data Connect
Тип PostgreSQL по умолчанию Поддерживаемые типы PostgreSQL
(псевдоним в скобках)
Нить GraphQL текст текст
бит(n), варбит(n)
символ(n), varchar(n)
Инт GraphQL инт Int2 (smallint, smallserial),
int4 (целое, целое, последовательное)
Плавать GraphQL float8 float4 (действительный)
float8 (двойная точность)
числовой (десятичный)
Булев GraphQL булев булев
UUID Обычай uuid uuid
Int64 Обычай bigint int8 (bigint, bigserial)
числовой (десятичный)
Дата Обычай дата дата
Временная метка Обычай временная меткаtz

временная меткаtz

Примечание: информация о местном часовом поясе не сохраняется.
PostgreSQL преобразует и сохраняет такие временные метки в формате UTC.

Вектор Обычай вектор

вектор

См. раздел Выполнение поиска сходства векторов с помощью Vertex AI .

  • List GraphQL отображается в одномерный массив.
    • Например, [Int] отображается в int5[] , [Any] отображается в jsonb[] .
    • Data Connect не поддерживает вложенные массивы.

Эквивалентная схема 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);

Следующие шаги

Вас может заинтересовать: