設計 Data Connect 結構定義

您可以使用 Firebase Data Connect 設計 GraphQL 結構定義,代表應用程式所需的資料模型。Data Connect 會將這個結構定義轉換為支援應用程式的 PostgreSQL 適用的 Cloud SQL 執行個體。接著,您會編寫查詢和變動,與後端介面互動,並將這些作業封裝至連接器,以便從用戶端程式碼使用資料。

Data Connect 提供 AI 工具,協助您設計及導入結構定義。本指南將介紹架構設計的重要概念,協助您在開始開發應用程式時,支援及輔助標準和 AI 輔助工作流程,並持續提供協助

入門指南介紹了 PostgreSQL 的電影評論應用程式結構定義。

本指南會進一步開發該結構定義,並提供與最終電影評論應用程式結構定義對應的 SQL 清單

電影評論應用程式的結構定義

假設您要建構一項服務,讓使用者提交及查看電影評論。

這類應用程式需要初始結構定義,才能支援基本查詢。您稍後會擴充這個結構定義,建立複雜的關聯式查詢。

Data Connect 中,您將定義 GraphQL 型別,以定義用戶端可查詢及操控的資料形狀。編寫結構定義時,您的型別會轉換為 PostgreSQL 適用的 Cloud SQL 資料表,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 主要純量伺服器值

主要純量是簡潔的物件 ID,Data Connect 會根據結構定義中的主要欄位自動組裝。主要純量與效率有關,可讓您在單一呼叫中,找到資料的身分和結構相關資訊。當您想對新記錄執行連續動作,且需要將專屬 ID 傳遞至後續作業時,這些方法特別實用。此外,當您想存取關係鍵以執行其他更複雜的作業時,這些方法也很有幫助。

使用伺服器值,您就能有效讓伺服器根據 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
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 布林值 布林值
UUID 自訂 uuid uuid
Int64 自訂 bigint int8 (bigint、bigserial)
numeric (decimal)
日期 自訂 date 日期
時間戳記 自訂 timestamptz

timestamptz

注意:系統不會儲存當地時區資訊。
PostgreSQL 會轉換這類時間戳記,並以世界標準時間儲存。

列舉 自訂 enum

列舉

向量 自訂 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);

後續步驟

你可能感興趣的內容: