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 สร้างขึ้นโดยอัตโนมัติ จากฟิลด์คีย์ในสคีมา สเกลาร์หลักเกี่ยวข้องกับประสิทธิภาพ ซึ่งช่วยให้คุณค้นหาข้อมูลเกี่ยวกับตัวตนและ โครงสร้างของข้อมูลได้ในการเรียกครั้งเดียว โดยเฉพาะอย่างยิ่งเมื่อคุณต้องการดำเนินการตามลำดับกับระเบียนใหม่และต้องการตัวระบุที่ไม่ซ้ำกันเพื่อส่งไปยังการดำเนินการที่จะเกิดขึ้น รวมถึงเมื่อคุณต้องการเข้าถึงคีย์เชิงสัมพันธ์เพื่อดำเนินการที่ซับซ้อนเพิ่มเติม
ประเภทรหัส
ใน GraphQL ระบบจะกำหนดประเภท ID เป็นประเภททึบแสงที่แปลงเป็นอนุกรมเป็น
สตริง GraphQL ไม่สนใจรูปแบบรหัส แต่จะบังคับให้สตริงและจำนวนเต็ม
จากอินพุต
โดยปกติแล้วคีย์ PostgreSQL จะเป็นจำนวนเต็มหรือ UUID ไม่ใช่สตริง
Data Connect จะสร้างคีย์ดังกล่าวจากสคีมาของคุณโดยอัตโนมัติ คุณ
ปรับแต่งการสร้างคีย์ด้วยคำสั่ง @default ได้ตามที่แสดงในคำจำกัดความฟิลด์ id ของตาราง Actorid: ID! … @default(generate: "UUID")
ตารางข้อมูลเมตาของภาพยนตร์
ตอนนี้มาติดตามผู้กำกับภาพยนตร์ รวมถึงตั้งค่าความสัมพันธ์แบบหนึ่งต่อหนึ่งกับ 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 ประเภท | ประเภทในตัวของ GraphQL หรือ Data Connect ประเภทที่กำหนดเอง |
ประเภท PostgreSQL เริ่มต้น | ประเภท PostgreSQL ที่รองรับ (ชื่อแทนในวงเล็บ) |
|---|---|---|---|
| สตริง | GraphQL | ข้อความ | text bit(n), varbit(n) char(n), varchar(n) |
| Int | 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) |
| วันที่ | กำหนดเอง | วันที่ | วันที่ |
| การประทับเวลา | กำหนดเอง | timestamptz | timestamptz หมายเหตุ: ระบบจะไม่จัดเก็บข้อมูลเขตเวลาท้องถิ่น |
| การแจงนับ | กำหนดเอง | enum | enum |
| Vector | กำหนดเอง | vector | เวกเตอร์ |
- GraphQL
Listจะแมปกับอาร์เรย์แบบ 1 มิติ- เช่น
[Int]แมปกับint5[],[Any]แมปกับjsonb[] - Data Connect ไม่รองรับอาร์เรย์แบบซ้อน
- เช่น
การค้นหาและการเปลี่ยนแปลงโดยนัยและที่กำหนดไว้ล่วงหน้า
Data Connect คำค้นหาและการเปลี่ยนแปลงจะขยายชุดคำค้นหาโดยนัย และการเปลี่ยนแปลงโดยนัยที่ Data Connect สร้างขึ้นโดยอิงตาม ประเภทและความสัมพันธ์ของประเภทในสคีมา เครื่องมือในเครื่องจะสร้างการค้นหาและการเปลี่ยนแปลงโดยนัยทุกครั้งที่คุณแก้ไขสคีมา
ในกระบวนการพัฒนา คุณจะใช้คําค้นหาที่กําหนดไว้ล่วงหน้าและการเปลี่ยนแปลงที่กําหนดไว้ล่วงหน้าตามการดําเนินการโดยนัยเหล่านี้
การตั้งชื่อการค้นหาและการเปลี่ยนแปลงโดยนัย
Data Connect อนุมานชื่อที่เหมาะสมสำหรับการค้นหาและการเปลี่ยนแปลงโดยนัย
จากการประกาศประเภทสคีมา เช่น เมื่อทำงานกับแหล่งข้อมูล PostgreSQL
หากคุณกำหนดตารางชื่อ Movie เซิร์ฟเวอร์จะสร้างตารางต่อไปนี้โดยนัย
- การค้นหาสำหรับกรณีการใช้งานตารางเดียวที่มีชื่อที่ใช้งานง่าย
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
}
}
รวมถึงช่องอาร์เรย์
คุณทดสอบได้ว่าฟิลด์อาร์เรย์มีรายการที่ระบุหรือไม่
# 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 สามารถเข้าถึงข้อมูลตามความสัมพันธ์ระหว่างตารางได้ คุณสามารถใช้ความสัมพันธ์แบบออบเจ็กต์ (แบบหนึ่งต่อหนึ่ง) หรืออาร์เรย์ (แบบหนึ่งต่อหลายรายการ) ที่กำหนดไว้ในสคีมาเพื่อทำการค้นหาที่ซ้อนกันได้ กล่าวคือ ดึงข้อมูลประเภทหนึ่ง พร้อมกับข้อมูลจากประเภทที่ซ้อนกันหรือเกี่ยวข้อง
การค้นหาดังกล่าวใช้ไวยากรณ์ Data Connect _on_ และ _via ใน
การค้นหาโดยนัยที่สร้างขึ้น
คุณจะทำการแก้ไขสคีมาจากเวอร์ชันเริ่มต้นของเรา
หลายต่อหนึ่ง
มาเพิ่มรีวิวลงในแอปด้วย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")
}
การค้นหาแบบหลายต่อหนึ่ง
ตอนนี้มาดูการค้นหาที่มีการกำหนดนามแฝงเพื่อแสดงไวยากรณ์ _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
}
ค้นหาแบบตัวต่อตัว
คุณสามารถค้นหาโดยใช้ไวยากรณ์ _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);
ขั้นตอนต่อไปคืออะไร
- ดูวิธีเรียกใช้การค้นหาและการเปลี่ยนแปลงจาก Web SDK, Android SDK, iOS SDK และ Flutter SDK ที่สร้างขึ้นโดยอัตโนมัติ