设计 Data Connect 架构

借助 Firebase Data Connect,您可以设计一个 GraphQL 架构来表示 应用所需的数据模型。Data Connect 会将此架构转换为支持应用的 Cloud SQL for PostgreSQL 实例。然后,您可以编写查询和变更来与后端交互,并将这些操作捆绑到连接器中,以便从客户端代码中使用数据。

Data Connect 提供 AI 工具,可帮助您设计和实现 架构。本指南介绍了架构设计的重要概念,以便支持 和补充您的标准工作流和 AI 辅助工作流,当您 开始开发应用时以及 之后

快速入门指南介绍了适用于 PostgreSQL 的电影 评论应用架构。

本指南将进一步开发该架构,并提供与最终电影评论应用架构等效的 SQL 列表

电影评论应用的架构

假设您想要构建一项服务,让用户可以提交和查看电影评论。

您需要为此类应用提供初始架构,以支持基本查询。您稍后将扩展此架构以创建复杂的关系型查询。

Data Connect 中,您将定义 GraphQL 类型,以定义 客户端可以查询和操作的数据的形状。编写架构时,您的类型会转换为 Cloud SQL for 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 字段可以自动从身份验证中获取用户 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 会根据架构中的关键字段自动组装这些标识符。关键标量与效率有关,可让您通过一次调用即可找到有关数据身份和结构的信息。当您想要对新记录执行顺序操作并需要将唯一标识符传递给即将进行的操作时,以及当您想要访问关系型键以执行其他更复杂的操作时,它们尤其有用。

使用服务器值,您可以有效地让服务器根据 expr 实参中的特定服务器端 CEL 表达式,使用存储的值或可轻松计算的值动态填充 表中的字段。例如,您 可以使用操作请求中存储的时间定义一个字段,并在访问该字段时应用时间戳:updatedAt: Timestamp! @default(expr: "request.time")

ActorMovieActor 类型中处理多对多关系

处理完用户后,您可以返回来对电影数据进行建模。

接下来,您希望演员出演您的电影。

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](来自 movieactor 的外键字段)的组合。

# 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 会生成 moviemoviesactors_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 字段表示连接 ActorMovie 表的记录列表。使用此字段查询与给定 电影关联的所有演员。

使用此字段查询与给定 电影关联的所有演员。

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

考虑到这一点,您可以阅读有关如何在实现查询指南实现变更指南中使用这些字段来实现操作。

更高级的架构概念

枚举字段

Data Connect 支持映射到 PostgreSQL 枚举类型的枚举字段。借助枚举,您可以快速定义具有特定顺序的静态预定义值列表。

如需向架构添加枚举,请声明枚举及其预定义值,然后在类型中引用它。

enum AspectRatio {
   ACADEMY
   WIDESCREEN
   ANAMORPHIC
   IMAX
   "No information available on aspect ratio"
   UNAVAILABLE
}

type Movie
  @table {
  title: String! 
  genre: String
  description: String
  originalAspectRatio: AspectRatio! @default(value: WIDESCREEN)
  otherAspectRatios: [AspectRatio!]
  tags: [String]
  rating: Float
  imageUrl: String!
  releaseYear: Int
}

Movie 类型中,我们添加了一个枚举字段 originalAspectRatio,用于表示电影拍摄时的宽高比,以及另一个字段 otherAspectRatios,用于表示其他可用宽高比的列表。

管理对枚举字段的更改

您可以向枚举添加新值,但枚举列表的顺序非常重要,因此请谨慎插入新值。对枚举的唯一完全向后兼容的更改是将新值添加到值列表的末尾。值得注意的是,在之前发布的枚举之间插入新值或对现有值重新排序会更改查询中使用相对运算符(例如“小于”)时的相对顺序。移除或重命名值始终是向后不兼容的更改。

您绝不应重新排列枚举值列表中的值;排序非常重要,因为它会改变过滤条件的适用方式。

对枚举值的调整应谨慎进行,以免破坏旧版操作或客户端代码。移除或重命名枚举值时,请确保当前数据库中没有剩余的实例。

在操作和客户端代码中使用枚举字段

现在,您已向架构添加了枚举字段,可以在查询和客户端代码中使用此字段。

如需详细了解如何使用枚举编写查询,以及如何编写客户端以 允许从查询指南开始调整枚举,请参阅相关文档。

其他高级概念

如需了解基本但有用的类型和关系之外的内容,请参阅 参考文档中的示例。

支持的数据类型

Data Connect 支持以下标量数据类型,并使用 @col(dataType:) 将其分配给 PostgreSQL 类型。

Data Connect 类型 GraphQL 内置类型或
Data Connect 自定义类型
默认 PostgreSQL 类型 支持的 PostgreSQL 类型
(括号中的别名)
字符串 GraphQL text text
bit(n), varbit(n)
char(n), varchar(n)
整数 GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
浮点数 GraphQL float8 float4 (real)
float8 (double precision)
numeric (decimal)
布尔值 GraphQL boolean boolean
UUID 自定义 uuid uuid
Int64 自定义 bigint int8 (bigint, bigserial)
numeric (decimal)
日期 自定义 date date
时间戳 自定义 timestamptz

timestamptz

注意 :系统不会存储本地时区信息。
PostgreSQL 会将此类时间戳转换为 UTC 并存储。

枚举 自定义 enum

enum

向量 自定义 vector

vector

请参阅 使用 Vertex AI 执行向量相似度搜索

  • GraphQL List 映射到一维数组。
    • 例如,[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);

后续步骤

您可能感兴趣的内容: