Firebase Data Connect ให้คุณสร้างเครื่องมือเชื่อมต่อสำหรับ PostgreSQL ได้ ที่มีการจัดการด้วย Google Cloud SQL เครื่องมือเชื่อมต่อเหล่านี้เป็นการรวมสคีมา การค้นหา และการเปลี่ยนรูปแบบสําหรับการใช้ข้อมูล
คู่มือเริ่มต้นใช้งานได้แนะนำสคีมาแอปรีวิวภาพยนตร์สําหรับ PostgreSQL และคู่มือนี้จะเจาะลึกวิธีออกแบบสคีมาData Connectสําหรับ PostgreSQL
คู่มือนี้จับคู่คำค้นหา Data Connect รายการและการกลายพันธุ์กับสคีมา ตัวอย่าง เหตุใดจึงต้องพูดถึงการค้นหา (และการกลายพันธุ์) ในคู่มือเกี่ยวกับสคีมา Data Connect เช่นเดียวกับแพลตฟอร์มอื่นๆ ที่ใช้ GraphQL Firebase Data Connect เป็นแพลตฟอร์มการพัฒนาแบบเน้นการค้นหา ดังนั้นในฐานะนักพัฒนาซอฟต์แวร์ คุณจะต้องคำนึงถึงข้อมูลที่จำเป็นสำหรับลูกค้าในโมเดลข้อมูล ซึ่งจะส่งผลอย่างมากต่อสคีมาข้อมูลที่พัฒนาขึ้นสำหรับโปรเจ็กต์
คู่มือนี้เริ่มต้นด้วยสคีมาสำหรับรีวิวภาพยนตร์ใหม่ ก็จะครอบคลุมคำค้นหาและการกลายพันธุ์ มาจากสคีมานั้น และสุดท้ายจะแสดงข้อมูล SQL เทียบเท่ากับสคีมาหลักของ Data Connect
สคีมาสำหรับแอปรีวิวภาพยนตร์
สมมติว่าคุณต้องการสร้างบริการที่ให้ผู้ใช้ส่งและดูภาพยนตร์ได้ รีวิว
คุณต้องมีสคีมาเริ่มต้นสำหรับแอปดังกล่าว คุณจะขยายสคีมานี้ในภายหลัง เพื่อสร้างการค้นหาเชิงสัมพันธ์ที่ซับซ้อน
ตารางภาพยนตร์
สคีมาสำหรับภาพยนตร์มีคำสั่งหลักๆ เช่น
@table
ซึ่งช่วยให้เราตั้งชื่อการดำเนินการได้โดยใช้อาร์กิวเมนต์singular
และplural
@col
เพื่อตั้งชื่อคอลัมน์อย่างชัดแจ้ง@default
เพื่ออนุญาตให้ตั้งค่าเริ่มต้น
# Movies
type Movie
@table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
title: String!
releaseYear: Int @col(name: "release_year")
genre: String
rating: Int @col(name: "rating")
description: String @col(name: "description")
}
ค่าของเซิร์ฟเวอร์และค่าสเกลาร์ของคีย์
ก่อนดูแอปรีวิวภาพยนตร์ เราขอแนะนําData Connect ค่าเซิร์ฟเวอร์และสเกลาร์คีย์
การใช้ค่าเซิร์ฟเวอร์ช่วยให้เซิร์ฟเวอร์ป้อนข้อมูลในช่องของตารางแบบไดนามิกได้อย่างมีประสิทธิภาพโดยใช้ค่าที่เก็บไว้หรือค่าที่คำนวณได้ทันทีตามนิพจน์ฝั่งเซิร์ฟเวอร์ที่เฉพาะเจาะจง เช่น คุณสามารถกําหนดช่องที่มีการใช้การประทับเวลาเมื่อมีการเข้าถึงช่องโดยใช้นิพจน์ updatedAt: Timestamp! @default(expr: "request.time")
สเกลาร์คีย์คือตัวระบุออบเจ็กต์ที่สั้นกระชับซึ่ง Data Connect โดยอัตโนมัติ ประกอบจากช่องคีย์ในสคีมา สเกลาร์ที่สำคัญคือเรื่องประสิทธิภาพ ทำให้คุณพบข้อมูลเกี่ยวกับข้อมูลประจำตัว และ สำหรับข้อมูลของคุณ ซึ่งจะเป็นประโยชน์อย่างยิ่งเมื่อคุณต้องการ การดำเนินการตามลำดับในระเบียนใหม่ และต้องมีตัวระบุที่ไม่ซ้ำกันเพื่อส่งไปยัง การดำเนินการที่กำลังจะมาถึง รวมถึงเมื่อคุณต้องการเข้าถึงคีย์ที่เกี่ยวข้อง ดำเนินการที่ซับซ้อนมากขึ้นได้
ตารางข้อมูลเมตาของภาพยนตร์
ตอนนี้มาติดตามผู้กำกับภาพยนตร์และสร้างความสัมพันธ์แบบ 1:1 กับ Movie
เพิ่มคำสั่ง @ref
เพื่อกำหนดความสัมพันธ์
# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata
@table(
name: "MovieMetadata"
) {
# @ref creates a field in the current table (MovieMetadata) that holds the
# primary key of the referenced type
# In this case, @ref(fields: "id") is implied
movie: Movie! @ref
# movieId: UUID <- this is created by the above @ref
director: String @col(name: "director")
}
Actor และ MovieActor
ถัดไป คุณต้องการให้นักแสดงแสดงในภาพยนตร์ และเนื่องจากคุณมีความสัมพันธ์แบบหลายต่อหลายรายการระหว่างภาพยนตร์กับนักแสดง ให้สร้างตารางการรวม
# 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(name: "Actors", singular: "actor", plural: "actors") {
id: UUID! @col(name: "actor_id") @default(expr: "uuidV4()")
name: String! @col(name: "name", dataType: "varchar(30)")
}
# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary key(s) of this table
# In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
# @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
# In this case, @ref(fields: "id") is implied
movie: Movie! @ref
# movieId: UUID! <- this is created by the above @ref, see: implicit.gql
actor: Actor! @ref
# actorId: UUID! <- this is created by the above @ref, see: implicit.gql
role: String! @col(name: "role") # "main" or "supporting"
# optional other fields
}
ผู้ใช้
สุดท้ายคือผู้ใช้แอป
# Users
# Suppose a user can leave reviews for movies
# user:reviews is a one to many relationship, movie:reviews is a one to many relationship, movie:user is a many to many relationship
type User
@table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
auth: String @col(name: "user_auth") @default(expr: "auth.uid")
username: String! @col(name: "username", dataType: "varchar(30)")
# The following are generated from the @ref in the Review table
# reviews_on_user
# movies_via_Review
}
ประเภทข้อมูลที่รองรับ
Data Connect รองรับประเภทข้อมูลเชิงเดี่ยวต่อไปนี้ โดยมีการกำหนดค่าให้กับประเภท PostgreSQL โดยใช้ @col(dataType:)
Data Connect type | ประเภทในตัวของ GraphQL หรือ ประเภทที่กำหนดเองData Connect |
ประเภท PostgreSQL เริ่มต้น | ประเภท PostgreSQL ที่รองรับ (ชื่อแทนในวงเล็บ) |
---|---|---|---|
สตริง | GraphQL | ข้อความ | ข้อความ บิต(n), varbit(n) char(n), varchar(n) |
Int | GraphQL | int | Int2 (เล็ก, ซีเรียลเล็ก), int4 (จำนวนเต็ม, int, อนุกรม) |
ทศนิยม | กราฟ QL | Float 8 | Float4 (จริง) Float8 (ความแม่นยำ 2 เท่า) ตัวเลข (ทศนิยม) |
บูลีน | กราฟ QL | boolean | boolean |
UUID | กำหนดเอง | uuid | uuid |
Int64 | กำหนดเอง | Bigint | int8 (bigint, bigserial) numeric (decimal) |
วันที่ | กำหนดเอง | วันที่ | วันที่ |
การประทับเวลา | กำหนดเอง | timestamptz | timestamptz หมายเหตุ: ระบบจะไม่จัดเก็บข้อมูลเขตเวลาท้องถิ่น |
เวกเตอร์ | กำหนดเอง | vector | เวกเตอร์ |
- GraphQL
List
จะแมปกับอาร์เรย์ 1 มิติ- เช่น
[Int]
แมปกับint5[]
,[Any]
แมปกับjsonb[]
- Data Connect ไม่รองรับอาร์เรย์ที่ซ้อนกัน
- เช่น
การค้นหาและการดัดแปลงแบบนัยและที่กําหนดไว้ล่วงหน้า
ข้อความค้นหาและการกลายพันธุ์ Data Connect ของคุณจะขยายชุดของ implicit การค้นหาและการเปลี่ยนแปลงโดยนัยที่ Data Connect สร้างขึ้นโดยอิงจาก ประเภทและความสัมพันธ์ของประเภทในสคีมา ข้อความค้นหาที่ไม่เจาะจงและการเปลี่ยนแปลง สร้างขึ้นโดยเครื่องมือภายในเมื่อใดก็ตามที่คุณแก้ไขสคีมา
ในกระบวนการพัฒนา คุณจะใช้การค้นหาที่กำหนดไว้ล่วงหน้าและ การกลายพันธุ์ที่กำหนดไว้ล่วงหน้าจากการดำเนินการโดยนัยเหล่านี้
การค้นหาโดยนัยและการตั้งชื่อการเปลี่ยนแปลง
Data Connect จะอนุมานชื่อที่เหมาะสมสำหรับการค้นหาและการดัดแปลงโดยนัยจากประกาศประเภทสคีมา เช่น การทำงานกับ PostgreSQL
ถ้าคุณกำหนดตารางชื่อ Movie
เซิร์ฟเวอร์จะสร้าง implicit:
- คำค้นหาสำหรับ Use Case ตารางเดียวที่มีชื่อเรียกได้ง่าย
movie
(คำเอกพจน์ สำหรับการเรียกข้อมูลผลลัพธ์แต่ละรายการที่ส่งผ่านอาร์กิวเมนต์ เช่นeq
) และmovies
(คำพหูพจน์ ในการเรียกข้อมูลรายการผลลัพธ์ ที่ส่งอาร์กิวเมนต์ เช่นgt
และการดำเนินการเช่นorderby
) Data Connect ยังสร้างการค้นหาสำหรับหลายตาราง การดำเนินการเชิงสัมพันธ์ที่มีชื่ออย่างชัดแจ้ง เช่นactors_on_movies
หรือactors_via_actormovie
- การกลายพันธุ์ชื่อ
movie_insert
,movie_upsert
...
ภาษาคําจํากัดความสคีมายังช่วยให้คุณกําหนดชื่อการดำเนินการได้อย่างชัดเจนโดยใช้อาร์กิวเมนต์คําสั่ง singular
และ plural
การค้นหาฐานข้อมูลรีวิวภาพยนตร์
คุณกำหนดการค้นหา Data Connect ด้วยประกาศประเภทการดำเนินการค้นหา ชื่อการดำเนินการ อาร์กิวเมนต์การดำเนินการเป็น 0 รายการขึ้นไป และคำสั่งที่มีอาร์กิวเมนต์เป็น 0 รายการขึ้นไป
ในการเริ่มต้นอย่างรวดเร็ว ตัวอย่างการค้นหา listEmails
ไม่ได้ใช้พารามิเตอร์ แน่นอน
ในหลายกรณี ข้อมูลที่ส่งไปยังช่องการค้นหาจะเป็นแบบไดนามิก คุณสามารถใช้ไวยากรณ์ $variableName
เพื่อทํางานกับตัวแปรในฐานะองค์ประกอบหนึ่งของคําจํากัดความการค้นหา
ดังนั้นข้อความค้นหาต่อไปนี้จึงมี
- คำจำกัดความของประเภท
query
- ชื่อการดำเนินการ (การค้นหา)
ListMoviesByGenre
- อาร์กิวเมนต์การดำเนินการ
$genre
ตัวแปรเดียว - คําสั่งเดียว
@auth
query ListMoviesByGenre($genre: String!) @auth(level: USER)
อาร์กิวเมนต์การค้นหาทุกรายการต้องมีการประกาศประเภท ประเภทในตัว เช่น String
หรือประเภทที่กำหนดเองซึ่งกำหนดโดยสคีมา เช่น Movie
เรามาลองดูลายเซ็นของคำค้นหาที่ซับซ้อนมากขึ้นกัน ปิดท้ายด้วยการแนะนำนิพจน์ความสัมพันธ์ที่มีประสิทธิภาพและกระชับซึ่งมีอยู่ในคําค้นหาโดยนัยที่คุณนำไปต่อยอดในคําค้นหาที่กําหนดไว้ล่วงหน้าได้
สเกลาร์หลักในการค้นหา
แต่ก่อนอื่น โปรดดูหมายเหตุเกี่ยวกับสเกลาร์หลัก
Data Connect ระบุประเภทพิเศษสำหรับสเกลาร์คีย์ที่ระบุโดย
_Key
เช่น ประเภทของค่าสเกลาร์ของคีย์สําหรับตาราง Movie
คือ
Movie_Key
คุณเรียกข้อมูลสเกลาร์ที่สำคัญเป็นการตอบสนองที่แสดงผลโดยการเปลี่ยนแปลงโดยนัยส่วนใหญ่ หรือ แน่นอนว่ามาจากข้อความค้นหาที่คุณได้ดึงข้อมูล ฟิลด์ทั้งหมดที่จำเป็นในการสร้าง คีย์สเกลาร์
การค้นหาอัตโนมัติเอกพจน์ เช่น movie
ในตัวอย่างที่ทำงานอยู่ของเรารองรับคีย์
อาร์กิวเมนต์ที่ยอมรับสเกลาร์คีย์
คุณอาจส่งผ่านสเกลาร์คีย์เป็นลิเทอรัล แต่คุณกําหนดตัวแปรเพื่อส่งค่าสเกลาร์คีย์เป็นอินพุตได้
query GetMovie($myKey: Movie_Key!) {
movie(key: $myKey) { title }
}
ซึ่งสามารถอยู่ในคำขอ JSON เช่นนี้ (หรือการจัดเรียงแบบอื่นๆ รูปแบบต่อไปนี้
{
# …
"variables": {
"myKey": {"foo": "some-string-value", "bar": 42}
}
}
เนื่องจากการแยกวิเคราะห์สเกลาร์ที่กำหนดเอง คุณจึงสร้าง Movie_Key
โดยใช้ไวยากรณ์ออบเจ็กต์ซึ่งอาจมีตัวแปรได้ ซึ่งจะเป็นประโยชน์มากเมื่อคุณต้องการ
เพื่อแยกคอมโพเนนต์แต่ละรายการเป็นตัวแปรต่างๆ ด้วยเหตุผลบางอย่าง
การใช้ชื่อแทนในการค้นหา
Data Connect รองรับการแอบอ้างเป็น GraphQL ในการค้นหา คุณใช้อีเมลแทนเพื่อเปลี่ยนชื่อข้อมูลที่แสดงในผลการค้นหาได้ คำขอ คำค้นหา Data Connect รายการสามารถใช้ตัวกรองหลายรายการหรือใช้คำค้นหาอื่นๆ ได้ การส่งคำขอไปยังเซิร์ฟเวอร์อย่างมีประสิทธิภาพรายการเดียว โดยออกคำขอหลายรายการ "การค้นหาย่อย" พร้อมกัน หากไม่ต้องการให้ชื่อซ้ำกันในชุดข้อมูลที่แสดงผล ใช้ชื่อแทนเพื่อแยกแยะข้อความค้นหาย่อย
ต่อไปนี้คือการค้นหาที่นิพจน์ใช้ชื่อแทน mostPopular
query ReviewTopPopularity($genre: String) {
mostPopular: review(first: {
where: {genre: {eq: $genre}},
orderBy: {popularity: DESC}
}) { … }
}
การค้นหาแบบง่ายด้วยตัวกรอง
การค้นหา Data Connect จะแมปกับตัวกรองและลำดับ SQL ทั่วไปทั้งหมด การดำเนินงาน
โอเปอเรเตอร์ where
และ orderBy
(คำค้นหาแบบเอกพจน์และพหูพจน์)
แสดงแถวที่ตรงกันทั้งหมดจากตาราง (และการเชื่อมโยงที่ฝังอยู่) แสดงผลอาร์เรย์เปล่าหากไม่มีระเบียนที่ตรงกับตัวกรอง
query MovieByTopRating($genre: String) {
mostPopular: movies(
where: { genre: { eq: $genre } }, orderBy: { rating: DESC }
) {
# graphql: list the fields from the results to return
id
title
genre
description
}
}
query MoviesByReleaseYear($min: Int, $max: Int) {
movies(where: {releaseYear: {le: $max, ge: $min}}, orderBy: [{releaseYear: ASC}]) { … }
}
โอเปอเรเตอร์ limit
และ offset
(ข้อความค้นหาเอกพจน์หรือพหูพจน์)
คุณสามารถใส่เลขหน้าในผลการค้นหา ระบบยอมรับอาร์กิวเมนต์เหล่านี้ แต่ไม่ยอมรับ แสดงผลในผลลัพธ์
query MoviesTop10 {
movies(orderBy: [{ rating: DESC }], limit: 10) {
# graphql: list the fields from the results to return
title
}
}
include สำหรับฟิลด์อาร์เรย์
คุณสามารถทดสอบว่าช่องอาร์เรย์มีรายการที่ระบุ
# Filter using arrays and embedded fields.
query ListMoviesByTag($tag: String!) {
movies(where: { tags: { includes: $tag }}) {
# graphql: list the fields from the results to return
id
title
}
}
การดำเนินการกับสตริงและนิพจน์ทั่วไป
คำค้นหาของคุณสามารถใช้การดำเนินการค้นหาและเปรียบเทียบสตริงทั่วไป ซึ่งรวมถึง นิพจน์ทั่วไป โปรดทราบว่าคุณกำลังรวมการดำเนินการหลายรายการเข้าด้วยกันเพื่อเพิ่มประสิทธิภาพ และทำให้การดำเนินการเหล่านั้นชัดเจนขึ้นด้วยการใช้อีเมลแทน
query MoviesTitleSearch($prefix: String, $suffix: String, $contained: String, $regex: String) {
prefixed: movies(where: {title: {startsWith: $prefix}}) {...}
suffixed: movies(where: {title: {endsWith: $suffix}}) {...}
contained: movies(where: {title: {contains: $contained}}) {...}
matchRegex: movies(where: {title: {pattern: {regex: $regex}}}) {...}
}
or
และ and
สำหรับตัวกรองแบบคอมโพส
ใช้ or
และ and
สำหรับตรรกะที่ซับซ้อนมากขึ้น
query ListMoviesByGenreAndGenre($minRating: Int!, $genre: String) {
movies(
where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] }
) {
# graphql: list the fields from the results to return
title
}
}
การค้นหาที่ซับซ้อน
การค้นหา Data Connect รายการสามารถเข้าถึงข้อมูลตามความสัมพันธ์ระหว่าง คุณสามารถใช้ความสัมพันธ์แบบออบเจ็กต์ (แบบ 1:1) หรืออาร์เรย์ (แบบ 1:หลายรายการ) ที่กําหนดไว้ในสคีมาเพื่อสร้างการค้นหาที่ฝังอยู่ เช่น ดึงข้อมูลสําหรับประเภทหนึ่งพร้อมกับข้อมูลจากประเภทที่ฝังอยู่หรือที่เกี่ยวข้อง
การค้นหาดังกล่าวใช้ไวยากรณ์ Data Connect _on_
และ _via
ที่เป็นค่าเริ่มต้นในการค้นหาโดยนัยที่สร้างขึ้น
คุณจะทำการเปลี่ยนแปลงสคีมาจากเวอร์ชันเริ่มต้น
หลายต่อ 1
มาเพิ่มรีวิวในแอปของเราด้วยตาราง Review
และการแก้ไข User
กัน
# Users
# Suppose a user can leave reviews for movies
# user:reviews is a one to many relationship,
# movie:reviews is a one to many relationship,
# movie:user is a many to many relationship
type User
@table(name: "Users", singular: "user", plural: "users", key: ["id"]) {
id: UUID! @col(name: "user_id") @default(expr: "uuidV4()")
auth: String @col(name: "user_auth") @default(expr: "auth.uid")
username: String! @col(name: "username", dataType: "varchar(30)")
# The following are generated from the @ref in the Review table
# reviews_on_user
# movies_via_Review
}
# Reviews
type Review @table(name: "Reviews", key: ["movie", "user"]) {
id: UUID! @col(name: "review_id") @default(expr: "uuidV4()")
user: User! @ref
movie: Movie! @ref
rating: Int
reviewText: String
reviewDate: Date! @default(expr: "request.time")
}
ค้นหาหลายรายการต่อ 1 รายการ
ตอนนี้เราจะมาดูคำค้นหาพร้อมชื่อแทน เพื่อแสดงไวยากรณ์ _via_
query UserMoviePreferences($username: String!) @auth(level: USER) {
users(where: { username: { eq: $username } }) {
likedMovies: movies_via_review(where: { rating: { ge: 4 } }) {
title
genre
description
}
dislikedMovies: movies_via_review(where: { rating: { le: 2 } }) {
title
genre
description
}
}
}
แบบตัวต่อตัว
คุณจะเห็นรูปแบบ ด้านล่างนี้เป็นสคีมาที่มีการแก้ไขเพื่อแสดงภาพ
# Movies
type Movie
@table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
title: String!
releaseYear: Int @col(name: "release_year")
genre: String
rating: Int @col(name: "rating")
description: String @col(name: "description")
tags: [String] @col(name: "tags")
}
# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata
@table(
name: "MovieMetadata"
) {
# @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
# In this case, @ref(fields: "id") is implied
movie: Movie! @ref
# movieId: UUID <- this is created by the above @ref
director: String @col(name: "director")
}
extend type MovieMetadata {
movieId: UUID! # matches primary key of referenced type
...
}
extend type Movie {
movieMetadata: MovieMetadata # can only be non-nullable on ref side
# conflict-free name, always generated
movieMetadatas_on_movie: MovieMetadata
}
การค้นหาสำหรับ 1 ต่อ 1
คุณค้นหาได้โดยใช้ไวยากรณ์ _on_
# One to one
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
movieMetadatas_on_movie {
director
}
}
}
หลายต่อหลาย
ภาพยนตร์ต้องมีนักแสดง และนักแสดงก็ต้องการภาพยนตร์ ตารางเหล่านี้มีความสัมพันธ์แบบหลายต่อหลายที่คุณจำลองได้ด้วยMovieActors
ตารางการรวม
# MovieActors Join Table Definition
type MovieActors @table(
key: ["movie", "actor"] # join key triggers many-to-many generation
) {
movie: Movie!
actor: Actor!
}
# generated extensions for the MovieActors join table
extend type MovieActors {
movieId: UUID!
actorId: UUID!
}
# Extensions for Actor and Movie to handle many-to-many relationships
extend type Movie {
movieActors: [MovieActors!]! # standard many-to-one relation to join table
actors: [Actor!]! # many-to-many via join table
movieActors_on_actor: [MovieActors!]!
# since MovieActors joins distinct types, type name alone is sufficiently precise
actors_via_MovieActors: [Actor!]!
}
extend type Actor {
movieActors: [MovieActors!]! # standard many-to-one relation to join table
movies: [Movie!]! # many-to-many via join table
movieActors_on_movie: [MovieActors!]!
movies_via_MovieActors: [Movie!]!
}
การค้นหาแบบหลายต่อหลาย
มาดูตัวอย่างคําค้นหาที่มีการเปลี่ยนชื่อเพื่อแสดงไวยากรณ์ _via_
query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) {
movie(id: $movieId) {
mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
name
}
supportingActors: actors_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
name
}
}
actor(id: $actorId) {
mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) {
title
}
supportingRoles: movies_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
title
}
}
}
การกลายพันธุ์สําหรับฐานข้อมูลรีวิวภาพยนตร์
ดังที่กล่าวไปแล้ว เมื่อคุณกำหนดตารางในสคีมา Data Connect ระบบจะสร้างการเปลี่ยนแปลงโดยนัยพื้นฐานสำหรับแต่ละตาราง
type Movie @table { ... }
extend type Mutation {
# Insert a row into the movie table.
movie_insert(...): Movie_Key!
# Upsert a row into movie."
movie_upsert(...): Movie_Key!
# Update a row in Movie. Returns null if a row with the specified id/key does not exist
movie_update(...): Movie_Key
# Update rows based on a filter in Movie.
movie_updateMany(...): Int!
# Delete a single row in Movie. Returns null if a row with the specified id/key does not exist
movie_delete(...): Movie_Key
# Delete rows based on a filter in Movie.
movie_deleteMany(...): Int!
}
ซึ่งจะช่วยให้คุณใช้เคส CRUD หลักที่ซับซ้อนมากขึ้นได้ พูดเร็วๆ 5 ครั้ง
สร้าง
มาเริ่มสร้างผลงานแบบพื้นฐานกัน
# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
movie_insert(data: {
title: $title
releaseYear: $releaseYear
genre: $genre
rating: $rating
})
}
# Create a movie with default values
mutation CreateMovie2 {
movie_insert(data: {
title: "Sherlock Holmes"
releaseYear: 2009
genre: "Mystery"
rating: 5
})
}
หรืออัปเซิร์ต
# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
movie_upsert(data: {
title: $title
releaseYear: 2009
genre: "Mystery"
rating: 5
genre: "Mystery/Thriller"
})
}
ทำการอัปเดต
ข้อมูลอัปเดตมีดังนี้ โปรดิวเซอร์และผู้กำกับหวังเป็นอย่างยิ่งว่าค่าเฉลี่ยเหล่านั้น คะแนนเป็นไปตามเทรนด์
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$rating: Int!,
$description: String!
) {
movie_update(id: $id, data: {
genre: $genre
rating: $rating
description: $description
})
}
# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $ratingIncrement: Int!) {
movie_updateMany(
where: { genre: { eq: $genre } },
update: { rating: { inc: $ratingIncrement } }
)
}
ดำเนินการลบ
แน่นอนว่าคุณลบข้อมูลภาพยนตร์ได้ ผู้เก็บรักษาฟิล์มจะ ต้องการรักษาภาพยนตร์จริงไว้นานที่สุดเท่าที่จะเป็นไปได้
# Delete by key
mutation DeleteMovie($id: UUID!) {
movie_delete(id: $id)
}
คุณสามารถใช้ _deleteMany
ได้ที่นี่
# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
movie_deleteMany(where: { rating: { le: $minRating } })
}
เขียนการกลายพันธุ์ในความสัมพันธ์
ดูวิธีใช้การดัดแปลง _upsert
ที่ไม่ชัดแจ้งกับความสัมพันธ์
# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
movieMetadata_upsert(
data: { movie: { id: $movieId }, director: $director }
)
}
สคีมา 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);
ขั้นตอนถัดไปคือ
- ดูวิธีเรียกใช้คำค้นหาและการกลายพันธุ์จากที่ระบบสร้างขึ้นโดยอัตโนมัติ SDK ของเว็บ, Android SDK, iOS SDK และ Flutter SDK