Thiết kế giản đồ Data Connect

Với Firebase Data Connect, bạn thiết kế một giản đồ GraphQL đại diện cho mô hình dữ liệu cần thiết cho ứng dụng của mình. Data Connect chuyển đổi giản đồ này thành phiên bản Cloud SQL cho PostgreSQL hỗ trợ ứng dụng của bạn. Sau đó, bạn sẽ tạo các truy vấn và đột biến để giao tiếp với phần phụ trợ và gói các thao tác này thành trình kết nối để sử dụng dữ liệu từ mã ứng dụng.

Data Connect cung cấp công cụ AI để giúp bạn thiết kế và triển khai giản đồ. Hướng dẫn này giới thiệu các khái niệm quan trọng về thiết kế giản đồ để hỗ trợ và bổ sung cho quy trình làm việc tiêu chuẩn và quy trình làm việc được AI hỗ trợ khi bạn bắt đầu phát triển một ứng dụng, và hơn thế nữa.

Hướng dẫn Bắt đầu đã giới thiệu một giản đồ ứng dụng đánh giá phim cho PostgreSQL.

Hướng dẫn này sẽ phát triển thêm giản đồ đó và cung cấp danh sách SQL tương đương với giản đồ ứng dụng đánh giá phim cuối cùng.

Giản đồ cho ứng dụng đánh giá phim

Hãy tưởng tượng bạn muốn xây dựng một dịch vụ cho phép người dùng gửi và xem các bài đánh giá phim.

Bạn cần một giản đồ ban đầu cho ứng dụng như vậy để hỗ trợ các truy vấn cơ bản. Sau này, bạn sẽ mở rộng giản đồ này để tạo các truy vấn quan hệ phức tạp.

Trong Data Connect, bạn sẽ xác định các loại GraphQL để xác định hình dạng của dữ liệu mà ứng dụng có thể truy vấn và thao tác. Khi bạn viết giản đồ, các loại của bạn sẽ được dịch thành các bảng Cloud SQL cho PostgreSQL, thường là trong mối quan hệ trực tiếp giữa các loại GraphQL và bảng cơ sở dữ liệu, mặc dù có thể có các ánh xạ khác. Hướng dẫn này trình bày một số ví dụ từ cơ bản đến nâng cao hơn.

Xác định loại Movie cơ bản

Bạn có thể bắt đầu với loại Movie.

Giản đồ cho Movie chứa các chỉ thị cốt lõi như:

  • @table(name)@col(name) để tuỳ chỉnh tên bảng và cột SQL. Data Connect tạo tên snake_case nếu không được chỉ định.
  • @col(dataType) để tuỳ chỉnh các loại cột SQL.
  • @default để định cấu hình các giá trị mặc định của cột SQL trong quá trình chèn.

Để biết thêm thông tin chi tiết, hãy xem tài liệu tham khảo cho @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
}

Tự động lưu trữ dữ liệu người dùng quan trọng trong loại User

Ứng dụng của bạn sẽ theo dõi người dùng, vì vậy, bạn cần có loại User.

Chỉ thị @default đặc biệt hữu ích trong trường hợp này. Trường id ở đây có thể tự động lấy mã nhận dạng của người dùng từ quá trình xác thực: hãy lưu ý việc sử dụng @default(expr: "auth.uid") trong mẫu sau.

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

Các đại lượng vô hướng chính và giá trị máy chủ

Trước khi xem xét kỹ hơn về ứng dụng đánh giá phim, bạn cần giới thiệu Data Connect các đại lượng vô hướng chínhgiá trị máy chủ.

Các đại lượng vô hướng chính là các mã nhận dạng đối tượng ngắn gọn mà Data Connect tự động tập hợp từ các trường khoá trong giản đồ của bạn. Các đại lượng vô hướng chính là về hiệu quả, cho phép bạn tìm thấy thông tin về danh tính và cấu trúc dữ liệu của mình trong một lệnh gọi duy nhất. Chúng đặc biệt hữu ích khi bạn muốn thực hiện các hành động tuần tự trên các bản ghi mới và cần một mã nhận dạng duy nhất để chuyển đến các thao tác sắp tới, đồng thời khi bạn muốn truy cập vào các khoá quan hệ để thực hiện các thao tác phức tạp hơn.

Khi sử dụng giá trị máy chủ, bạn có thể cho phép máy chủ tự động điền các trường trong bảng bằng các giá trị được lưu trữ hoặc có thể tính toán dễ dàng theo các biểu thức CEL cụ thể phía máy chủ trong đối số expr. Ví dụ: bạn có thể xác định một trường có dấu thời gian được áp dụng khi trường được truy cập bằng thời gian được lưu trữ trong yêu cầu thao tác, updatedAt: Timestamp! @default(expr: "request.time").

Xử lý mối quan hệ nhiều-nhiều trong các loại ActorMovieActor

Sau khi xử lý người dùng, bạn có thể quay lại mô hình hoá dữ liệu phim.

Tiếp theo, bạn muốn các diễn viên đóng vai chính trong phim của mình.

Bảng Actor khá đơn giản.

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

Nếu bạn muốn các diễn viên đóng nhiều phim và phim có nhiều diễn viên, bạn sẽ cần một "bảng kết hợp".

Bảng MovieActor xử lý mối quan hệ nhiều-nhiều và khoá chính của bảng này là sự kết hợp của [movie, actor] (các trường khoá ngoại từ 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
}

Khi bạn xác định mối quan hệ SQL trên bảng có ràng buộc khoá ngoại, Data Connect sẽ tự động tạo trường tương ứng ở phía bên kia. Bạn không cần xác định trường ánh xạ ngược (ví dụ: từ Actor trở lại MovieActor).

Xử lý mối quan hệ một-một trong loại MovieMetadata

Bây giờ, hãy theo dõi các đạo diễn phim, cũng như thiết lập mối quan hệ một-một với Movie.

Bạn có thể sử dụng chỉ thị @ref để tuỳ chỉnh các ràng buộc khoá ngoại:

  • @ref(fields) chỉ định các trường khoá ngoại cần sử dụng.
  • @ref(references) chỉ định các trường được tham chiếu trong bảng đích (mặc định là khoá chính, nhưng các trường @unique cũng hoạt động). Đây là một lựa chọn nâng cao hơn ; Data Connect thường có thể suy luận điều này cho bạn.

Để biết thêm thông tin chi tiết, hãy xem tài liệu tham khảo cho @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
}

Sử dụng các trường được tạo từ giản đồ để xây dựng các thao tác

Các thao tác Data Connect sẽ mở rộng một tập hợp các trường do Data Connect tự động tạo dựa trên các loại và mối quan hệ giữa các loại trong giản đồ của bạn. Các trường này được tạo bởi công cụ cục bộ bất cứ khi nào bạn chỉnh sửa giản đồ.

Giả sử giản đồ của bạn chứa loại Movie và loại Actor được liên kết. Data Connect tạo các trường movie, movies, actors_on_movies và nhiều trường khác.

Truy vấn bằng trường
movie

Trường movie đại diện cho một bản ghi duy nhất trong bảng Movie.

Sử dụng trường này để truy vấn một bộ phim duy nhất theo khoá của bộ phim đó.

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

Truy vấn bằng trường
movies

Trường movies đại diện cho danh sách các bản ghi trong bảng Movie.

Sử dụng trường này để truy vấn nhiều bộ phim, ví dụ: tất cả các bộ phim có một năm nhất định.

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

Truy vấn bằng trường
actors_on_movies

Trường actors_on_movies đại diện cho danh sách các bản ghi kết nối các bảng ActorMovie. Sử dụng trường này để truy vấn tất cả các diễn viên được liên kết với một bộ phim nhất định.

Sử dụng trường này để truy vấn tất cả các diễn viên được liên kết với một bộ phim nhất định.

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

Với điều này, bạn có thể đọc cách triển khai các thao tác bằng các trường này trong hướng dẫn triển khai truy vấnhướng dẫn triển khai đột biến.

Các khái niệm nâng cao hơn về giản đồ

Trường liệt kê

Data Connect hỗ trợ các trường liệt kê ánh xạ tới các loại được liệt kê của PostgreSQL. Enum cho phép bạn nhanh chóng xác định danh sách các giá trị tĩnh, được xác định trước theo một thứ tự cụ thể.

Để thêm một enum vào giản đồ, hãy khai báo enum và các giá trị được xác định trước của enum đó, sau đó tham chiếu đến enum đó trong loại của bạn.

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
}

Trong loại Movie, chúng tôi đã thêm một trường enum originalAspectRatio cho tỷ lệ khung hình mà bộ phim được quay và một trường otherAspectRatios khác cho danh sách các tỷ lệ khung hình có sẵn khác.

Quản lý các thay đổi đối với trường liệt kê

Bạn có thể thêm các giá trị mới vào enum, nhưng thứ tự của danh sách enum có ý nghĩa rất quan trọng, vì vậy, hãy chèn các giá trị mới một cách khôn ngoan. Thay đổi duy nhất hoàn toàn tương thích ngược với enum là thêm một giá trị mới vào cuối danh sách giá trị. Đáng chú ý là việc chèn một giá trị mới giữa các enum đã xuất bản trước đó hoặc sắp xếp lại các giá trị hiện có sẽ thay đổi thứ tự tương đối khi các toán tử tương đối như "nhỏ hơn" được sử dụng trong các truy vấn. Việc xoá hoặc đổi tên giá trị luôn là một thay đổi không tương thích ngược.

Bạn không bao giờ được sắp xếp lại các giá trị trong danh sách giá trị enum; thứ tự là quan trọng vì nó thay đổi cách áp dụng tính năng lọc.

Bạn nên điều chỉnh các giá trị enum một cách cẩn thận để không làm hỏng các phiên bản cũ hơn của thao tác hoặc mã ứng dụng. Khi xoá hoặc đổi tên một giá trị enum, hãy đảm bảo không còn thực thể nào trong cơ sở dữ liệu hiện tại.

Sử dụng các trường enum trong các thao tác và trong mã ứng dụng

Giờ đây, khi đã thêm một trường enum vào giản đồ, bạn có thể sử dụng trường này trong các truy vấn và mã ứng dụng.

Tìm hiểu thêm về cách viết truy vấn bằng enum và cách viết ứng dụng để cho phép điều chỉnh enum bắt đầu trong hướng dẫn truy vấn.

Các khái niệm nâng cao khác

Để chuyển sang các loại và mối quan hệ cơ bản nhưng hữu ích, hãy tham khảo các ví dụ trong tài liệu tham khảo.

Loại dữ liệu được hỗ trợ

Data Connect hỗ trợ các loại dữ liệu vô hướng sau đây, với các phép gán cho các loại PostgreSQL bằng @col(dataType:).

Data Connect loại Loại tích hợp sẵn của GraphQL hoặc
Data Connect loại tuỳ chỉnh
Loại PostgreSQL mặc định Các loại PostgreSQL được hỗ trợ
(bí danh trong dấu ngoặc đơn)
Chuỗi GraphQL văn bản văn bản
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Nổi GraphQL float8 float4 (real)
float8 (double precision)
numeric (decimal)
Boolean GraphQL boolean boolean
mã nhận dạng duy nhất (UUID) Tuỳ chỉnh uuid uuid
Int64 Tuỳ chỉnh bigint int8 (bigint, bigserial)
numeric (decimal)
Ngày Tuỳ chỉnh ngày ngày
Dấu thời gian Tuỳ chỉnh timestamptz

timestamptz

Lưu ý: Thông tin múi giờ cục bộ không được lưu trữ.
PostgreSQL chuyển đổi và lưu trữ các dấu thời gian như vậy ở định dạng UTC.

Bảng liệt kê Tuỳ chỉnh enum

enum

Vectơ Tuỳ chỉnh vectơ

vectơ

Xem bài viết Thực hiện tìm kiếm mức độ tương đồng vectơ bằng Vertex AI.

  • List GraphQL ánh xạ tới một mảng một chiều.
    • Ví dụ: [Int] ánh xạ tới int5[], [Any] ánh xạ tới jsonb[].
    • Data Connect không hỗ trợ mảng lồng nhau.

Giản đồ SQL tương đương

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

Các bước tiếp theo

Bạn có thể quan tâm đến: