สร้างด้วย Firebase Data Connect

1. ก่อนที่คุณจะเริ่มต้น

แอป FriendlyMovies

ในโค้ดแล็บนี้ คุณจะได้ผสานรวม Firebase Data Connect กับฐานข้อมูล Cloud SQL เพื่อสร้างเว็บแอปรีวิวภาพยนตร์ แอปที่เสร็จสมบูรณ์จะแสดงให้เห็นว่า Firebase Data Connect ช่วยให้การสร้างแอปพลิเคชันที่ทำงานด้วย SQL เป็นเรื่องง่ายเพียงใด ซึ่งประกอบด้วยฟีเจอร์ต่อไปนี้

  • การตรวจสอบสิทธิ์: ใช้การตรวจสอบสิทธิ์ที่กำหนดเองสำหรับการค้นหาและการดัดแปลงของแอป เพื่อให้มั่นใจว่ามีเพียงผู้ใช้ที่ได้รับอนุญาตเท่านั้นที่โต้ตอบกับข้อมูลของคุณได้
  • สคีมา GraphQL: สร้างและจัดการโครงสร้างข้อมูลโดยใช้สคีมา GraphQL ที่ยืดหยุ่นซึ่งปรับให้เหมาะกับความต้องการของเว็บแอปรีวิวภาพยนตร์
  • การค้นหาและการเปลี่ยนรูปแบบ SQL: ดึงข้อมูล อัปเดต และจัดการข้อมูลใน Cloud SQL โดยใช้การค้นหาและการเปลี่ยนรูปแบบที่ทำงานด้วย GraphQL
  • การค้นหาขั้นสูงที่มีการจับคู่สตริงบางส่วน: ใช้ตัวกรองและตัวเลือกการค้นหาเพื่อค้นหาภาพยนตร์ตามช่องต่างๆ เช่น ชื่อ คำอธิบาย หรือแท็ก
  • ไม่บังคับ: การผสานรวมการค้นหาเวกเตอร์: เพิ่มฟังก์ชันการค้นหาเนื้อหาโดยใช้การค้นหาเวกเตอร์ของ Firebase Data Connect เพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่สมบูรณ์ตามข้อมูลและค่ากําหนด

ข้อกำหนดเบื้องต้น

คุณต้องมีความเข้าใจพื้นฐานเกี่ยวกับ JavaScript

สิ่งที่คุณจะได้เรียนรู้

  • ตั้งค่า Firebase Data Connect ด้วยโปรแกรมจำลองในเครื่อง
  • ออกแบบสคีมาข้อมูลโดยใช้ Data Connect และ GraphQL
  • เขียนและทดสอบการค้นหาและการกลายพันธุ์ต่างๆ สําหรับแอปรีวิวภาพยนตร์
  • ดูวิธีที่ Firebase Data Connect สร้างและใช้ SDK ในแอป
  • ติดตั้งใช้งานสคีมาและจัดการฐานข้อมูลอย่างมีประสิทธิภาพ

สิ่งที่ต้องมี

  • Git
  • โค้ด Visual Studio
  • ติดตั้ง Node.js โดยใช้ nvm-windows (Windows) หรือ nvm (macOS/Linux)
  • สร้างโปรเจ็กต์ Firebase ในคอนโซล Firebase หากยังไม่ได้สร้าง
  • (ไม่บังคับ) หากต้องการใช้การค้นหาเวกเตอร์ ให้อัปเกรดโปรเจ็กต์เป็นแพ็กเกจ Blaze

การตั้งค่าสภาพแวดล้อมในการพัฒนาซอฟต์แวร์

ส่วนนี้จะแนะนำการตั้งค่าสภาพแวดล้อมเพื่อเริ่มสร้างแอปรีวิวภาพยนตร์โดยใช้ Firebase Data Connect

ขั้นตอนที่ 1: โคลนที่เก็บโปรเจ็กต์

เริ่มต้นด้วยการทำโคลนที่เก็บโปรเจ็กต์และติดตั้ง Dependency ที่จำเป็น

git clone https://github.com/firebaseextended/codelab-dataconnect-web
cd codelab-dataconnect-web
cd ./app && npm i
npm run dev
  1. หลังจากเรียกใช้คําสั่งเหล่านี้แล้ว ให้เปิด http://localhost:5173 ในเบราว์เซอร์เพื่อดูเว็บแอปที่ทํางานในเครื่อง ซึ่งทำหน้าที่เป็นอินเทอร์เฟซส่วนหน้าสำหรับการสร้างแอปรีวิวภาพยนตร์และการโต้ตอบกับฟีเจอร์ต่างๆ

93f6648a2532c606.png

ขั้นตอนที่ 2: เปิดโปรเจ็กต์ใน Visual Studio Code

เปิดโฟลเดอร์ codelab-dataconnect-web ที่โคลนโดยใช้ Visual Studio Code ซึ่งคุณจะกำหนดสคีมา เขียนการค้นหา และทดสอบฟังก์ชันการทำงานของแอปได้

ขั้นตอนที่ 3: ติดตั้งส่วนขยาย Firebase Data Connect ใน Visual Studio

หากต้องการใช้ฟีเจอร์ Data Connect ให้ติดตั้งส่วนขยาย Visual Studio สำหรับ Firebase Data Connect หรือติดตั้งจาก Visual Studio Code Marketplace หรือค้นหาภายใน VS Code

  1. หรือติดตั้งจาก Visual Studio Code Marketplace หรือค้นหาภายใน VS Code

b03ee38c9a81b648.png

ขั้นตอนที่ 4: สร้างโปรเจ็กต์ Firebase

ไปที่คอนโซล Firebase เพื่อสร้างโปรเจ็กต์ Firebase ใหม่หากยังไม่มี จากนั้นทำดังนี้ในส่วนขยาย Firebase Data Connect ของ VSCode

  • คลิกปุ่มลงชื่อเข้าใช้
  • คลิกเชื่อมต่อโปรเจ็กต์ Firebase แล้วเลือกโปรเจ็กต์ที่สร้างในคอนโซล Firebase

4bb2fbf8f9fac29b.png

ขั้นตอนที่ 5: เริ่มโปรแกรมจำลอง Firebase

ในส่วนขยาย Firebase Data Connect ของ VSCode ให้คลิก "เริ่มโปรแกรมจำลอง" และตรวจสอบว่าโปรแกรมจำลองทํางานอยู่ในเทอร์มินัล

6d3d95f4cb708db1.png

2. ตรวจสอบโค้ดฐานเริ่มต้น

ในส่วนนี้ คุณจะได้สำรวจส่วนสําคัญของโค้ดเริ่มต้นของแอป แม้ว่าแอปจะขาดฟังก์ชันบางอย่าง แต่การทำความเข้าใจโครงสร้างโดยรวมก็มีประโยชน์

โครงสร้างโฟลเดอร์และไฟล์

ภาพรวมโดยย่อของโครงสร้างโฟลเดอร์และไฟล์ของแอปมีดังนี้

dataconnect/

มีการกำหนดค่า Firebase Data Connect, ตัวเชื่อมต่อ (ซึ่งกำหนดการค้นหาและการดัดแปลง) และไฟล์สคีมา

  • schema/schema.gql: กำหนดสคีมา GraphQL
  • connector/queries.gql: คําค้นหาที่จําเป็นสําหรับแอป
  • connector/mutations.gql: การกลายพันธุ์ที่จําเป็นสําหรับแอป
  • connector/connector.yaml: ไฟล์การกําหนดค่าสําหรับการสร้าง SDK

app/src/

มีตรรกะแอปพลิเคชันและการทำงานกับ Firebase Data Connect

  • firebase.ts: การกําหนดค่าเพื่อเชื่อมต่อกับแอป Firebase ในคอนโซล
  • lib/dataconnect-sdk/: โฟลเดอร์นี้มี SDK ที่สร้างขึ้น คุณสามารถแก้ไขตำแหน่งการสร้าง SDK ในไฟล์ connector/connector.yaml และระบบจะสร้าง SDK โดยอัตโนมัติทุกครั้งที่คุณกำหนดการค้นหาหรือการดัดแปลง

3. การกําหนดสคีมาสําหรับรีวิวภาพยนตร์

ในส่วนนี้ คุณจะต้องกำหนดโครงสร้างและความสัมพันธ์ระหว่างเอนทิตีหลักในแ��ปพลิเคชันภาพยนตร์ในสคีมา เอนทิตี เช่น Movie, User, Actor และ Review จะแมปกับตารางฐานข้อมูล โดยมีการสร้างความสัมพันธ์โดยใช้คำสั่ง Firebase Data Connect และคำสั่งสคีมา GraphQL เมื่อติดตั้งใช้งานแล้ว แอปของคุณจะพร้อมจัดการทุกอย่างตั้งแต่การค้นหาภาพยนตร์ที่ได้รับคะแนนสูงสุดและการกรองตามประเภท ไปจนถึงการอนุญาตให้ผู้ใช้แสดงความคิดเห็น เลือกรายการโปรด สํารวจภาพยนตร์ที่คล้ายกัน หรือค้นหาภาพยนตร์แนะนำตามข้อความที่ป้อนผ่านการค้นหาเวกเตอร์

เอนทิตีหลักและความสัมพันธ์

ประเภท Movie มีรายละเอียดสำคัญ เช่น ชื่อ ประเภท และแท็ก ซึ่งแอปใช้สำหรับการค้นหาและโปรไฟล์ภาพยนตร์ ประเภท User จะติดตามการโต้ตอบของผู้ใช้ เช่น รีวิวและรายการโปรด Reviews เชื่อมต่อผู้ใช้กับภาพยนตร์ โดยให้แอปแสดงการให้คะแนนและความคิดเห็นที่ผู้ใช้สร้างขึ้น

ความสัมพันธ์ระหว่างภาพยนตร์ นักแสดง และผู้ใช้ทำให้แอปมีความหลากหลายมากขึ้น ตารางการรวม MovieActor ช่วยแสดงรายละเอียดนักแสดงและผลงานภาพยนตร์ของนักแสดง ประเภท FavoriteMovie ช่วยให้ผู้ใช้สามารถตั้งค่าภาพยนตร์เป็นรายการโปรด เพื่อให้แอปแสดงรายการโปรดที่ปรับเปลี่ยนในแบบของคุณและไฮไลต์รายการยอดนิยม

ตารางภาพยนตร์

ประเภท Movie จะกำหนดโครงสร้างหลักสำหรับเอนทิตีภาพยนตร์ ซึ่งรวมถึงช่องต่างๆ เช่น ชื่อ ประเภท ปีเผยแพร่ และการจัดประเภท

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type Movie
  @table {
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
}

สรุปประเด็นสำคัญ:

  • id: UUID ที่ไม่ซ้ำกันสำหรับ��าพยนตร์แต่ละเรื่อง ซึ่งสร้างขึ้นโดยใช้ @default(expr: "uuidV4()")

ตาราง MovieMetadata

ประเภท MovieMetadata จะสร้างความสัมพันธ์แบบ 1:1 กับประเภท Movie ซึ่งรวมถึงข้อมูลเพิ่มเติม เช่น ผู้กำกับภาพยนตร์

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type MovieMetadata
  @table {
  # @ref creates a field in the current table (MovieMetadata)
  # It is a reference that holds the primary key of the referenced type
  # In this case, @ref(fields: "movieId", references: "id") is implied
  movie: Movie! @ref
  # movieId: UUID <- this is created by the above @ref
  director: String
}

สรุปประเด็นสำคัญ:

  • Movie! @ref: อ้างอิงประเภท Movie ซึ่งจะสร้างความสัมพันธ์ของคีย์ต่างประเทศ

ตาราง Actor

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type Actor @table {
  id: UUID!
  imageUrl: String! 
  name: String! @col(name: "name", dataType: "varchar(30)")
}

ประเภท Actor แสดงถึงนักแสดงในฐานข้อมูลภาพยนตร์ โดยที่นักแสดงแต่ละคนอาจเป็นส่วนหนึ่งของภาพยนตร์หลายเรื่อง ซึ่งจะทำให้เกิดความสัมพันธ์แบบหลายต่อหลายรายการ

ตาราง MovieActor

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

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!
  # movieId: UUID! <- this is created by the implied @ref, see: implicit.gql

  actor: Actor!
  # actorId: UUID! <- this is created by the implied  @ref, see: implicit.gql

  role: String! # "main" or "supporting"
}

สรุปประเด็นสำคัญ:

  • movie: อ้างอิงประเภท Movie โดยจะสร้างคีย์ต่างประเทศ movieId: UUID โดยปริยาย
  • actor: อ้างอิงประเภท Actor ซึ่งจะสร้างคีย์ต่างประเทศ actorId: UUID โดยปริยาย
  • role: กำหนดบทบาทของนักแสดงในภาพยนตร์ (เช่น "main" หรือ "supporting")

ตารางผู้ใช้

ประเภท User จะกำหนดเอนทิตีผู้ใช้ที่โต้ตอบกับภาพยนตร์ด้วยการเขียนรีวิวหรือตั้งภาพยนตร์เป็นรายการโปรด

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type User
  @table {
  id: String! @col(name: "auth_uid")
  username: String! @col(dataType: "varchar(50)")
  # The following are generated from the @ref in the Review table
  # reviews_on_user 
  # movies_via_Review
}

ตาราง FavoriteMovie

ประเภท FavoriteMovie คือตารางการรวมที่จัดการความสัมพันธ์แบบหลายต่อหลายรายการระหว่างผู้ใช้กับภาพยนตร์หรือนักแสดงคนโปรด แต่ละตารางจะลิงก์ User กับ Movie

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type FavoriteMovie
  @table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
  # @ref is implicit
  user: User!
  movie: Movie!
}

สรุปประเด็นสำคัญ:

  • movie: อ้างอิงประเภท Movie โดยจะสร้างคีย์ต่างประเทศ movieId: UUID โดยปริยาย
  • user: อ้างอิงประเภทผู้ใช้ ��ร���างคีย์ต่างประเทศ userId: UUID โดยนัย

ตารางรีวิว

ประเภทรีวิวแสดงถึงเอนทิตีรีวิวและลิงก์ประเภทผู้ใช้และภาพยนตร์ในความสัมพันธ์แบบหลายต่อหลายรายการ (ผู้ใช้ 1 คนสามารถเขียนรีวิวได้หลายรายการ และภาพยนตร์แต่ละเรื่องมีรีวิวได้หลายรายการ)

คัดลอกและวางข้อมูลโค้ดลงในไฟล์ dataconnect/schema/schema.gql

type Review @table(name: "Reviews", key: ["movie", "user"]) {
  id: UUID! @default(expr: "uuidV4()")
  user: User!
  movie: Movie!
  rating: Int
  reviewText: String
  reviewDate: Date! @default(expr: "request.time")
}

สรุปประเด็นสำคัญ:

  • user: อ้างอิงผู้ใช้ที่เขียนรีวิว
  • movie: อ้างอิงภาพยนตร์ที่รีวิว
  • reviewDate: ตั้งค่าเป็นเวลาที่สร้างรีวิวโดยอัตโนมัติโดยใช้ @default(expr: "request.time")

ฟิลด์และค่าเริ่มต้นที่สร้างขึ้นโดยอัตโนมัติ

สคีมาใช้นิพจน์อย่าง @default(expr: "uuidV4()") เพื่อสร้างรหัสที่ไม่ซ้ำกันและการประทับเวลาโดยอัตโนมัติ ตัวอย่างเช่น ช่องรหัสในประเภทภาพยนตร์และรีวิวจะป้อนข้อมูล UUID โดยอัตโนมัติเมื่อมีการสร้างระเบียนใหม่

เมื่อกําหนดสคีมาแล้ว แอปภาพยนตร์ของคุณจะมีรากฐานที่มั่นคงสําหรับโครงสร้างและความสัมพันธ์ของข้อมูล

4. ดึงข้อมูลภาพยนตร์ยอดนิยมและภาพยนตร์ล่าสุด

แอป FriendlyMovies

ในส่วนนี้ คุณจะแทรกข้อมูลภาพยนตร์จำลองลงในโปรแกรมจำลองในเครื่อง จากนั้นใช้ตัวเชื่อมต่อ (การค้นหา) และโค้ด TypeScript เพื่อเรียกใช้ตัวเชื่อมต่อเหล่านี้ในเว็บแอปพลิเคชัน เมื่อดำเนินการเสร็จสิ้น แอปจะดึงข้อมูลและแสดงภาพยนตร์ยอดนิยมและภาพยนตร์ล่าสุดแบบไดนามิกจากฐานข้อมูลได้โดยตรง

การแทรกข้อมูลภาพยนตร์ นักแสดง และรีวิวจำลอง

  1. ใน VSCode ให้เปิด dataconnect/moviedata_insert.gql ตรวจสอบว่าโปรแกรมจําลองในชิ้นงาน Firebase Data Connect ทํางานอยู่
  2. คุณควรเห็นปุ่มเรียกใช้ (ในเครื่อง) ที่ด้านบนของไฟล์ คลิกเพื่อแทรกข้อมูลภาพยนตร์จำลองลงในฐานข้อมูล

e424f75e63bf2e10.png

  1. ตรวจสอบเทอร์มินัลการดำเนินการเชื่อมต่อข้อมูลเพื่อยืนยันว่าเพิ่มข้อมูลเรียบร้อยแล้ว

e0943d7704fb84ea.png

การใช้เครื่องมือเชื่อมต่อ

  1. เปิด dataconnect/movie-connector/queries.gql คุณจะเห็นการค้นหา ListMovies พื้นฐานในความคิดเห็น
query ListMovies @auth(level: PUBLIC) {
  movies {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

การค้นหานี้จะดึงข้อมูลภาพยนตร์ทั้งหมดและรายละเอียดของภาพยนตร์ (เช่น รหัส ชื่อ ปีเผยแพร่) แต่จะไม่จัดเรียงภาพยนตร์

  1. แทนที่การค้นหา ListMovies ด้วยข้อความค้นหาด้านล่างเพื่อเพิ่มตัวเลือกการจัดเรียงและจํากัด
# List subset of fields for movies
query ListMovies($orderByRating: OrderDirection, $orderByReleaseYear: OrderDirection, $limit: Int) @auth(level: PUBLIC) {
  movies(
    orderBy: [
      { rating: $orderByRating },
      { releaseYear: $orderByReleaseYear }
    ]
    limit: $limit
  ) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    tags
    description
  }
}

คลิกปุ่มเรียกใช้ (ในเครื่อง) เพื่อเรียกใช้การค้นหากับฐานข้อมูลในเครื่อง นอกจากนี้ คุณยังป้อนตัวแปรการค้นหาในแผงการกําหนดค่าก่อนเรียกใช้ได้

c4d947115bb11b16.png

สรุปประเด็นสำคัญ:

  • movies(): ช่องการค้นหา GraphQL สำหรับการดึงข้อมูลภาพยนตร์จากฐานข้อมูล
  • orderByRating: พารามิเตอร์สำหรับจัดเรียงภาพยนตร์ตามการจัดประเภท (จากน้อยไปมาก/มากไปน้อย)
  • orderByReleaseYear: พารามิเตอร์สำหรับจัดเรียงภาพยนตร์ตามปีที่ออกฉาย (จากน้อยไปมาก/มากไปน้อย)
  • limit: จำกัดจำนวนภาพยนตร์ที่แสดง

การผสานรวมการค้นหาในเว็บแอป

ในส่วนนี้ คุณจะใช้การค้นหาที่กําหนดไว้ในส่วนก่อนหน้าในเว็บแอป เครื่องจำลอง Firebase Data Connect จะสร้าง SDK ตามข้อมูลในไฟล์ .gql (schema.gql, queries.gql, mutations.gql) และ connector.yaml คุณเรียกใช้ SDK เหล่านี้ได้โดยตรงในแอปพลิเคชัน

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์คำสั่งการนําเข้าที่ด้านบน
import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";

ฟังก์ชัน listMovies, ประเภทคำตอบ ListMoviesData และ enum OrderDirection คือ SDK ทั้งหมดที่โปรแกรมจำลอง Firebase Data Connect สร้างขึ้นตามสคีมาและการค้นหาที่คุณกำหนดไว้ก่อนหน้านี้

  1. แทนที่ฟังก์ชัน handleGetTopMovies และ handleGetLatestMovies ด้วยโค้ดต่อไปนี้
// Fetch top-rated movies
export const handleGetTopMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByRating: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching top movies:", error);
    return null;
  }
};

// Fetch latest movies
export const handleGetLatestMovies = async (
  limit: number
): Promise<ListMoviesData["movies"] | null> => {
  try {
    const response = await listMovies({
      orderByReleaseYear: OrderDirection.DESC,
      limit,
    });
    return response.data.movies;
  } catch (error) {
    console.error("Error fetching latest movies:", error);
    return null;
  }
};

สรุปประเด็นสำคัญ:

  • listMovies: ฟังก์ชันที่สร้างขึ้นโดยอัตโนมัติซึ่งเรียกใช้การค้นหา listMovies เพื่อดึงข้อมูลรายการภาพยนตร์ ซึ่งรวมถึงตัวเลือกการจัดเรียงตามการจัดประเภทหรือปีเผยแพร่ รวมถึงการจำกัดจำนวนผลการค้นหา
  • ListMoviesData: ประเภทผลลัพธ์ที่ใช้แสดงภาพยนตร์ยอดนิยม 10 อันดับแรกและภาพยนตร์ล่าสุดในหน้าแรก

ดูการใช้งานจริง

โหลดเว็บแอปซ้ำเพื่อดูการค้นหา ตอนนี้หน้าแรกจะแสดงรายการภาพยนตร์แบบไดนามิก โดยดึงข้อมูลจากฐานข้อมูลในเครื่องโดยตรง คุณจะเห็นภาพยนตร์ยอดนิยมและภาพยนตร์ล่าสุดปรากฏขึ้นอย่างราบรื่น ซึ่งแสดงข้อมูลที่คุณเพิ่งตั้งค่า

5. การแสดงรายละเอียดภาพยนตร์และนักแสดง

ในส่วนนี้ คุณจะใช้ฟังก์ชันการทำ��านเพื่อดึงข้อมูลโดยละเอียดของภาพยนตร์หรือนักแสดงโดยใช้รหัสที่ไม่ซ้ำกัน ซึ่งไม่เพียงแต่จะดึงข้อมูลจากตารางที่เกี่ยวข้องเท่านั้น แต่ยังรวมตารางที่เกี่ยวข้องเพื่อแสดงรายละเอียดที่ครอบคลุม เช่น รีวิวภาพยนตร์และผลงานภาพยนตร์ของนักแสดง

ac7fefa7ff779231.png

การใช้เครื่องมือเชื่อมต่อ

  1. เปิด dataconnect/movie-connector/queries.gql ในโปรเจ็กต์
  2. เพิ่มข้อความค้นหาต่อไปนี้เพื่อดึงรายละเอียดภาพยนตร์และนักแสดง
# Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
 movie(id: $id) {
    id
    title
    imageUrl
    releaseYear
    genre
    rating
    description
    tags
    metadata: movieMetadatas_on_movie {
      director
    }
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      name
      imageUrl
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      name
      imageUrl
    }
    reviews: reviews_on_movie {
      id
      reviewText
      reviewDate
      rating
      user {
        id
        username
      }
    }
  }
 }

# Get actor by id
query GetActorById($id: UUID!) @auth(level: PUBLIC) {
  actor(id: $id) {
    id
    name
    imageUrl
    mainActors: movies_via_MovieActor(where: { role: { eq: "main" } }) {
      id
      title
      genre
      tags
      imageUrl
    }
    supportingActors: movies_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      id
      title
      genre
      tags
      imageUrl
    }
  }
}
  1. บันทึกการเปลี่ยนแปลงและตรวจสอบข้อความค้นหา

สรุปประเด็นสำคัญ:

  • movie()/actor(): ช่องการค้นหา GraphQL สำหรับการดึงข้อมูลภาพยนตร์หรือนักแสดงรายการเดียวจากตารางภาพยนตร์หรือนักแสดง
  • _on_: ตัวเลือกนี้ช่วยให้เข้าถึงฟิลด์จากประเภทที่เชื่อมโยงซึ่งมีความสัมพันธ์ของคีย์ต่างประเทศได้โดยตรง เช่น reviews_on_movie จะดึงข้อมูลรีวิวทั้งหมดที่เกี่ยวข้องกับภาพยนตร์หนึ่งๆ
  • _via_: ใช้เพื่อไปยังส่วนต่างๆ ของความสัมพันธ์แบบหลายต่อหลายรายการผ่านตารางการรวม ตัวอย่างเช่น actors_via_MovieActor จะเข้าถึงประเภทนักแสดงผ่านตารางการรวม MovieActor และเงื่อนไข where จะกรองนักแสดงตามบทบาท (เช่น "main" หรือ "supporting")

ในแผงการดําเนินการของ Data Connect คุณสามารถทดสอบการค้นหาได้โดยป้อนรหัสจำลอง เช่น

{"id": "550e8400-e29b-41d4-a716-446655440000"}

คลิกเรียกใช้ (ในเ��รื่อง) สำหรับ GetMovieById เพื่อเรียกข้อมูลเกี่ยวกับ "Quantum Paradox" (ภาพยนตร์จำลองที่รหัสข้างต้นเกี่ยวข้อง)

1b08961891e44da2.png

การผสานรวมการค้นหาในเว็บแอป

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้
import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
import { GetActorByIdData, getActorById } from "@movie/dataconnect";
  1. แทนที่ฟังก์ชัน handleGetMovieById และ handleGetActorById ด้วยโค้ดต่อไปนี้
// Fetch movie details by ID
export const handleGetMovieById = async (
  movieId: string
) => {
  try {
    const response = await getMovieById({ id: movieId });
    if (response.data.movie) {
      return response.data.movie;
    }
    return null;
  } catch (error) {
    console.error("Error fetching movie:", error);
    return null;
  }
};

// Calling generated SDK for GetActorById
export const handleGetActorById = async (
  actorId: string
): Promise<GetActorByIdData["actor"] | null> => {
  try {
    const response = await getActorById({ id: actorId });
    if (response.data.actor) {
      return response.data.actor;
    }
    return null;
  } catch (error) {
    console.error("Error fetching actor:", error);
    return null;
  }
};

สรุปประเด็นสำคัญ:

  • getMovieById / getActorById: ฟังก์ชันเหล่านี้สร้างขึ้นโดยอัตโนมัติซึ่งเรียกใช้การค้นหาที่คุณกำหนดไว้ เพื่อดึงข้อมูลโดยละเอียดสำหรับภาพยนตร์หรือนักแสดงที่เฉพาะเจาะจง
  • GetMovieByIdData / GetActorByIdData: ประเภทผลลัพธ์เหล่านี้ใช้เพื่อแสดงรายละเอียดภาพยนตร์และนักแสดงในแอป

ดูการใช้งานจริง

จากนั้นไปที่หน้าแรกของเว็บแอป คลิกภาพยนตร์เพื่อดูรายละเอียดทั้งหมด รวมถึงนักแสดงและรีวิว ซึ่งเป็นข้อมูลที่ดึงมาจากตารางที่เกี่ยวข้อง ในทำนองเดียวกัน การคลิกที่นักแสดงจะแสดงภาพยนตร์ที่นักแสดงคนนั้นแสดง

6. การจัดการการตรวจสอบสิทธิ์ของผู้ใช้

ในส่วนนี้ คุณจะใช้ฟังก์ชันการลงชื่อเข้าใช้และออกจากระบบของผู้ใช้โดยใช้ Firebase Authentication นอกจากนี้ คุณจะใช้ข้อมูลการตรวจสอบสิทธิ์ Firebase เพื่อดึงข้อมูลหรืออัปเดตข้อมูลผู้ใช้ใน Firebase DataConnect โดยตรงได้ เพื่อให้การจัดการผู้ใช้ภายในแอปเป็นไปอย่างปลอดภัย

9890838045d5a00e.png

การใช้เครื่องมือเชื่อมต่อ

  1. เป��ด mutations.gql ใน dataconnect/movie-connector/
  2. เพิ่มการดัดแปลงต่อไปนี้เพื่อสร้างหรืออัปเดตผู้ใช้ที่ตรวจสอบสิทธิ์ในปัจจุบัน
# Create or update the current authenticated user
mutation UpsertUser($username: String!) @auth(level: USER) {
  user_upsert(
    data: {
      id_expr: "auth.uid"
      username: $username
    }
  )
}

สิ่งสำคัญที่เรียนรู้:

  • id_expr: "auth.uid": ตัวเลือกนี้ใช้ auth.uid ซึ่งมาจาก Firebase Authentication โดยตรง ไม่ใช่จากผู้ใช้หรือแอป ซึ่งจะเพิ่มความปลอดภัยอีกชั้นโดยการจัดการรหัสผู้ใช้อย่างปลอดภัยและอัตโนมัติ

ถัดไป ให้เปิด queries.gql ใน dataconnect/movie-connector/

เพิ่มข้อความค้นหาต่อไปนี้เพื่อดึงข้อมูลผู้ใช้ปัจจุบัน

# Get user by ID
query GetCurrentUser @auth(level: USER) {
  user(key: { id_expr: "auth.uid" }) {
    id
    username
    reviews: reviews_on_user {
      id
      rating
      reviewDate
      reviewText
      movie {
        id
        title
      }
    }
    favoriteMovies: favorite_movies_on_user {
      movie {
        id
        title
        genre
        imageUrl
        releaseYear
        rating
        description
        tags
        metadata: movieMetadatas_on_movie {
          director
        }
      }
    }
  }
}

สรุปประเด็นสำคัญ

  • auth.uid: ระบบจะดึงข้อมูลนี้มาจากการตรวจสอบสิทธิ์ Firebase โดยตรง เพื่อให้มั่นใจว่าเข้าถึงข้อมูลเฉพาะผู้ใช้ได้อย่างปลอดภัย
  • _on_ ฟิลด์: ฟิลด์เหล่านี้แสดงตารางการเข้าร่วม
  • reviews_on_user: ดึงข้อมูลรีวิวทั้งหมดที่เกี่ยวข้องกับผู้ใช้ ซึ่งรวมถึงรหัสและชื่อภาพยนตร์
  • favorite_movies_on_user: ดึงข้อมูลภาพยนตร์ทั้งหมดที่ผู้ใช้ทำเครื่องหมายว่าชื่นชอบ รวมถึงข้อมูลโดยละเอียด เช่น ประเภท ปี การจัดประเภท และข้อมูลเมตา

การผสานรวมการค้นหาในเว็บแอป

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้
import { upsertUser } from "@movie/dataconnect";
import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
  1. แทนที่ฟังก์ชัน handleAuthStateChange และ handleGetCurrentUser ด้วยโค้ดต่อไปนี้
// Handle user authentication state changes and upsert user
export const handleAuthStateChange = (
  auth: any,
  setUser: (user: User | null) => void
) => {
  return onAuthStateChanged(auth, async (user) => {
    if (user) {
      setUser(user);
      const username = user.email?.split("@")[0] || "anon";
      await upsertUser({ username });
    } else {
      setUser(null);
    }
  });
};

// Fetch current user profile
export const handleGetCurrentUser = async (): Promise<
  GetCurrentUserData["user"] | null
> => {
  try {
    const response = await getCurrentUser();
    return response.data.user;
  } catch (error) {
    console.error("Error fetching user profile:", error);
    return null;
  }
};

สรุปประเด็นสำคัญ:

  • handleAuthStateChange: ฟังการเปลี่ยนแปลงสถานะการตรวจสอบสิทธิ์ เมื่อผู้ใช้ลงชื่อเข้าใช้ ระบบจะตั้งค่าข้อมูลของผู้ใช้และเรียกใช้ upsertUser mutation เพื่อสร้างหรืออัปเดตข้อมูลของผู้ใช้ในฐานข้อมูล
  • handleGetCurrentUser: ดึงข้อมูลโปรไฟล์ของผู้ใช้ปัจจุบันโดยใช้การค้นหา getCurrentUser ซึ่งจะดึงข้อมูลรีวิวและภาพยนตร์โปรดของผู้ใช้

ดูการใช้งานจริง

ตอนนี้ให้คลิกปุ่ม "ลงชื่อเข้าใช้ด้วย Google" ในแถบนําทาง คุณลงชื่อเข้าใช้ได้โดยใช้โปรแกรมจำลอง Firebase Auth หลังจากลงชื่อเข้าใช้แล้ว ให้คลิก "โปรไฟล์ของฉัน" ขณะนี้ส่วนนี้จะว่างเปล่า แต่คุณได้สร้างรากฐานสำหรับการจัดการข้อมูลที่เจาะจงผู้ใช้ในแอปแล้ว

7. การติดตั้งใช้งานการโต้ตอบของผู้ใช้

ในส่วนนี้ คุณจะใช้การโต้ตอบของผู้ใช้ในแอปรีวิวภาพยนตร์ ซึ่งจะช่วยให้ผู้ใช้จัดการภาพยนตร์ที่ชอบ รวมถึงเขียนหรือลบรีวิวได้

b3d0ac1e181c9de9.png

การใช้เครื่องมือเชื่อมต่อ

  1. เปิด mutations.gql ใน dataconnect/movie-connector/
  2. เพิ่มการกลายพันธุ์ต่อไปนี้เพื่อจัดการการทำให้ภาพยนตร์เป็นรายการโปรด
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

สรุปประเด็นสำคัญ:

  • userId_expr: "auth.uid": ใช้ auth.uid ซึ่ง Firebase Authentication เป็นผู้จัดหาโดยตรง เพื่อให้มั่นใจว่าจะมีเพียงข้อมูลของผู้ใช้ที่ตรวจสอบสิทธิ์เท่านั้นที่เข้าถึงหรือแก้ไขได้
  1. ถัดไป ให้เปิด queries.gql ใน dataconnect/movie-connector/
  2. เพิ่มการค้นหาต่อไปนี้เพื่อตรวจสอบว่าภาพยนตร์เป็นรายการโปรดหรือไม่
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
    movieId
  }
}

สรุปประเด็นสำคัญ:

  • auth.uid: ช่วยให้เข้าถึงข้อมูลที่เจาะจงผู้ใช้ได้อย่างปลอดภัยโดยใช้การตรวจสอบสิทธิ์ Firebase
  • favorite_movie: ตรวจสอบตารางการเข้าร่วม favorite_movies เพื่อดูว่าผู้ใช้ปัจจุบัน���ด้ทำเครื่องหมายภาพยนตร์ที่เฉพาะเจาะจงว่าเป็นรายการโปรดหรือไม่

การผสานรวมการค้นหาในเว็บแอป

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้
import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
  1. แทนที่ฟังก์ชัน handleAddFavoritedMovie, handleDeleteFavoritedMovie และ handleGetIfFavoritedMovie ด้วยโค้ดต่อไปนี้
// Add a movie to user's favorites
export const handleAddFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await addFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error adding movie to favorites:", error);
    throw error;
  }
};

// Remove a movie from user's favorites
export const handleDeleteFavoritedMovie = async (
  movieId: string
): Promise<void> => {
  try {
    await deleteFavoritedMovie({ movieId });
  } catch (error) {
    console.error("Error removing movie from favorites:", error);
    throw error;
  }
};

// Check if the movie is favorited by the user
export const handleGetIfFavoritedMovie = async (
  movieId: string
): Promise<boolean> => {
  try {
    const response = await getIfFavoritedMovie({ movieId });
    return !!response.data.favorite_movie;
  } catch (error) {
    console.error("Error checking if movie is favorited:", error);
    return false;
  }
};

สรุปประเด็นสำคัญ:

  • handleAddFavoritedMovie และ handleDeleteFavoritedMovie: ใช้การดัดแปลงเพื่อเพิ่มหรือนำภาพยนตร์ออกจากรายการโปรดของผู้ใช้อย่างปลอดภัย
  • handleGetIfFavoritedMovie: ใช้การค้นหา getIfFavoritedMovie เพื่อตรวจสอบว่าผู้ใช้ได้ทำเครื่องหมายภาพยนตร์ว่าเป็นรายการโปรดหรือไม่

ดูการใช้งานจริง

ตอนนี้คุณเพิ่มภาพยนตร์หรือรายการทีวีที่ชอบหรือไม่ชอบได้แล้วโดยคลิกไอคอนหัวใจในการ์ดภาพยนตร์และหน้ารายละเอียดภาพยนตร์ นอกจากนี้ คุณยังดูภาพยนตร์ที่ชอบในหน้าโปรไฟล์ได้ด้วย

การใช้รีวิวของผู้ใช้

ถัดไป คุณจะใช้ส่วนสำหรับจัดการรีวิวของผู้ใช้ในแอป

การใช้เครื่องมือเชื่อมต่อ

  1. ใน mutations.gql (dataconnect/movie-connector/mutations.gql): เพิ่มการกลายพันธุ์ต่อไปนี้
# Add a review for a movie
mutation AddReview($movieId: UUID!, $rating: Int!, $reviewText: String!)
@auth(level: USER) {
  review_insert(
    data: {
      userId_expr: "auth.uid"
      movieId: $movieId
      rating: $rating
      reviewText: $reviewText
      reviewDate_date: { today: true }
    }
  )
}

# Delete a user's review for a movie
mutation DeleteReview($movieId: UUID!) @auth(level: USER) {
  review_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

สรุปประเด็นสำคัญ:

  • userId_expr: "auth.uid": ตรวจสอบว่ารีวิวเชื่อมโยงกับผู้ใช้ที่ตรวจสอบสิทธิ์แล้ว
  • reviewDate_date: { today: true }: สร้างวันที่ปัจจุบันของการตรวจสอบโดยอัตโนมัติโดยใช้ DataConnect จึงไม่จำเป็นต้องป้อนข้อมูลด้วยตนเอง

การผสานรวมการค้นหาในเว็บแอป

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้
import { addReview, deleteReview } from "@movie/dataconnect";
  1. แทนที่ฟังก์ชัน handleAddReview และ handleDeleteReview ด้วยโค้ดต่อไปนี้
// Add a review to a movie
export const handleAddReview = async (
  movieId: string,
  rating: number,
  reviewText: string
): Promise<void> => {
  try {
    await addReview({ movieId, rating, reviewText });
  } catch (error) {
    console.error("Error adding review:", error);
    throw error;
  }
};

// Delete a review from a movie
export const handleDeleteReview = async (movieId: string): Promise<void> => {
  try {
    await deleteReview({ movieId });
  } catch (error) {
    console.error("Error deleting review:", error);
    throw error;
  }
};

สรุปประเด็นสำคัญ:

  • handleAddReview: เรียกใช้การดัดแปลง addReview เพื่อเพิ่มรีวิวสำหรับภาพยนตร์ที่ระบุ โดยลิงก์รีวิวกับผู้ใช้ที่ตรวจสอบสิทธิ์อย่างปลอดภัย
  • handleDeleteReview: ใช้การดัดแปลง deleteReview เพื่อนำรีวิวภาพยนตร์ของผู้ใช้ที่ตรวจสอบสิทธิ์ออก

ดูการใช้งานจริง

ตอนนี้ผู้ใช้สามารถเขียนรีวิวภาพยนตร์ในหน้ารายละเอียดภาพยนตร์ได้แล้ว นอกจากนี้ ผู้ใช้ยังดูและลบรีวิวของตนเองในหน้าโปรไฟล์ได้ด้วย ซึ่งช่วยให้ผู้ใช้ควบคุมการโต้ตอบกับแอปได้อย่างเต็มรูปแบบ

8. ตัวกรองขั้นสูงและการจับคู่ข้อความบางส่วน

ในส่วนนี้ คุณจะใช้ความสามารถในการค้นหาขั้นสูง ซึ่งช่วยให้ผู้ใช้ค้นหาภาพยนตร์ตามการจัดประเภทและปีที่เผยแพร่ที่หลากหลาย กรองตามประเภทและแท็ก ทำการจับคู่ข้อความบางส่วนในชื่อหรือคำอธิบาย และแม้แต่รวมตัวกรองหลายรายการเข้าด้วยกันเพื่อให้ได้ผลลัพธ์ที่แม่นยำยิ่งขึ้น

ece70ee0ab964e28.png

การใช้เครื่องมือเชื่อมต่อ

  1. เปิด queries.gql ใน dataconnect/movie-connector/
  2. เพิ่มข้อความค้นหาต่อไปนี้เพื่อรองรับความสามารถในการค้นหาที่หลากหลาย
# Search for movies, actors, and reviews
query SearchAll(
  $input: String
  $minYear: Int!
  $maxYear: Int!
  $minRating: Float!
  $maxRating: Float!
  $genre: String!
) @auth(level: PUBLIC) {
  moviesMatchingTitle: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { title: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  moviesMatchingDescription: movies(
    where: {
      _and: [
        { releaseYear: { ge: $minYear } }
        { releaseYear: { le: $maxYear } }
        { rating: { ge: $minRating } }
        { rating: { le: $maxRating } }
        { genre: { contains: $genre } }
        { description: { contains: $input } }
      ]
    }
  ) {
    id
    title
    genre
    rating
    imageUrl
  }
  actorsMatchingName: actors(where: { name: { contains: $input } }) {
    id
    name
    imageUrl
  }
  reviewsMatchingText: reviews(where: { reviewText: { contains: $input } }) {
    id
    rating
    reviewText
    reviewDate
    movie {
      id
      title
    }
    user {
      id
      username
    }
  }
}

สรุปประเด็นสำคัญ:

  • โอเปอเรเตอร์ _and: รวมเงื่อนไขหลายรายการในการค้นหารายการเดียว ซึ่งช่วยให้กรองการค้นหาตามฟิลด์ต่างๆ ได้ เช่น releaseYear, rating และ genre
  • โอเปอเรเตอร์ contains: ค้นหาข้อความที่ตรงกันบางส่วนภายในช่อง ในข้อความค้นหานี้ ระบบจะค้นหารายการที่ตรงกันภายใน title, description, name หรือ reviewText
  • ประโยค where: ระบุเงื่อนไขในการกรองข้อมูล ส่วนแต่ละส่วน (ภาพยนตร์ นักแสดง รีวิว) ใช้ประโยค where เพื่อกำหนดเกณฑ์ที่เฉพาะเจาะจงสำหรับการค้นหา

การผสานรวมการค้นหาในเว็บแอป

  1. ใน MovieService (app/src/lib/MovieService.tsx) ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้
import { searchAll, SearchAllData } from "@movie/dataconnect";
  1. แทนที่ฟังก์ชัน handleSearchAll ด้วยโค้ดต่อไปนี้
// Function to perform the search using the query and filters
export const handleSearchAll = async (
  searchQuery: string,
  minYear: number,
  maxYear: number,
  minRating: number,
  maxRating: number,
  genre: string
): Promise<SearchAllData | null> => {
  try {
    const response = await searchAll({
      input: searchQuery,
      minYear,
      maxYear,
      minRating,
      maxRating,
      genre,
    });

    return response.data;
  } catch (error) {
    console.error("Error performing search:", error);
    return null;
  }
};

สรุปประเด็นสำคัญ:

  • handleSearchAll: ฟังก์ชันนี้ใช้การค้นหา searchAll เพื่อค้นหาตามข้อมูลที่ผู้ใช้ป้อน โดยกรองผลลัพธ์ตามพารามิเตอร์ต่างๆ เช่น ปี การให้คะแนน ประเภท และการจับคู่ข้อความบางส่วน

ดูการใช้งานจริง

ไปที่หน้า "การค้นหาขั้นสูง" จากแถบนาบในเว็บแอป ตอนนี้คุณค้นหาภาพยนตร์ นักแสดง และรีวิวได้โดยใช้ตัวกรองและอินพุตต่างๆ เพื่อรับผลการค้นหาที่ละเอียดและปรับให้เหมาะกับคุณ

9. ไม่บังคับ: ติดตั้งใช้งานในระบบคลาวด์ (ต้องมีการเรียกเก็บเงิน)

เมื่อคุณทําซ้ำการพัฒนาซอฟต์แวร์ภายในแล้ว ก็ถึงเวลาที่จะติดตั้งสคีมา ข้อมูล และการค้นหาลงในเซิร์ฟเวอร์ ซึ่งทําได้โดยใช้ส่วนขยาย Firebase Data Connect ใน VS Code หรือ Firebase CLI

การเพิ่มเว็บแอปในคอนโซล Firebase

  1. สร้างเว็บแอปในคอนโซล Firebase และจดรหัสแอปไว้

7030822793e4d75b.png

  1. ตั้งค่าเว็บแอปในคอนโซล Firebase โดยคลิก "เพิ่มแอป" คุณไม่จำเป็นต้องสนใจการตั้งค่า SDK และการกำหนดค่าในตอนนี้ แต่ให้จดจำออบเจ็กต์ firebaseConfig ที่สร้างขึ้น
  2. แทนที่ firebaseConfig ใน app/src/lib/firebase.tsx
const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "PROJECT_ID.firebaseapp.com",
  projectId: "PROJECT_ID",
  storageBucket: "PROJECT_ID.appspot.com",
  messagingSenderId: "SENDER_ID",
  appId: "APP_ID"
};
  1. สร้างเว็บแอป: ในโฟลเดอร์ app ให้ใช้ Vite เพื่อสร้างเว็บแอปสําหรับการทําให้การโฮสต์ใช้งานได้ โดยทําดังนี้
cd app
npm run build

ตั้งค่าการตรวจสอบสิทธิ์ Firebase ในคอนโซล

  1. ตั้งค่า Firebase Auth ด้วย Google Sign-In

62af2f225e790ef6.png

  1. (ไม่บังคับ) อนุญาตโดเมนสําหรับ (Firebase Auth) [https://firebase.google.com/docs/auth/web/hosting] ในคอนโซลโปรเจ็กต์ (เช่น http://127.0.0.1):
  • ในการตั้งค่าการตรวจสอบสิทธิ์ ให้เลือกโปรเจ็กต์แล้วไปที่ (โดเมนที่ได้รับอนุญาต) [https://firebase.google.com/docs/auth/web/hosting] คลิก "เพิ่มโดเมน" และใส่โดเมนในเครื่องของคุณไว้ในรายการ

c255098f12549886.png

ทำให้ใช้งานได้ด้วย Firebase CLI

  1. ใน dataconnect/dataconnect.yaml ให้ตรวจสอบว่ารหัสอินสแตนซ์ ฐานข้อมูล และรหัสบริการตรงกับโปรเจ็กต์ของคุณ
specVersion: "v1alpha"
serviceId: "your-service-id"
location: "us-central1"
schema:
  source: "./schema"
  datasource:
    postgresql:
      database: "your-database-id"
      cloudSql:
        instanceId: "your-instance-id"
connectorDirs: ["./movie-connector"]
  1. ตรวจสอบว่าคุณได้ตั้งค่า Firebase CLI กับโปรเจ็กต์แล้ว
npm i -g firebase-tools
firebase login --reauth
firebase use --add
  1. ในเทอร์มินัล ให้เรียกใช้คำสั่งต่อไปนี้เพื่อทำให้ใช้งานได้
firebase deploy --only dataconnect,hosting
  1. ใช้คําสั่งนี้เพื่อเปรียบเทียบการเปลี่ยนแปลงสคีมา
firebase dataconnect:sql:diff
  1. หากยอมรับการเปลี่ยนแปลงได้ ให้ใช้การเปลี่ยนแปลงดังกล่าวโดยทำดังนี้
firebase dataconnect:sql:migrate

อินสแตนซ์ Cloud SQL for PostgreSQL จะอัปเดตด้วยสคีมาและข้อมูลที่ติดตั้งใช้งานแล้วในขั้นสุดท้าย คุณสามารถตรวจสอบสถานะได้ในคอนโซล Firebase

ตอนนี้คุณควรเห����แ��������������ณ�����ยแพร่�����ู่ที่ your-project.web.app/ นอกจากนี้ คุณยังคลิกเรียกใช้ (เวอร์ชันที่ใช้งานจริง) ในแผง Firebase Data Connect ได้ เช่นเดียวกับที่ทำกับโปรแกรมจำลองในเครื่อง เพื่อเพิ่มข้อมูลลงในสภาพแวดล้อมเวอร์ชันที่ใช้งานจริง

10. ไม่บังคับ: การค้นหาเวกเตอร์ด้วย Firebase Data Connect

ในส่วนนี้ คุณจะเปิดใช้การค้นหาเวกเตอร์ในแอปรีวิวภาพยนตร์โดยใช้ Firebase Data Connect ฟีเจอร์นี้ช่วยให้ค้นหาตามเนื้อหาได้ เช่น ค้นหาภาพยนตร์ที่มีคำอธิบายคล้ายกันโดยใช้การฝังเวกเตอร์

4b5aca5a447d2feb.png

อัปเดตสคีมาให้รวมการฝังสำหรับช่อง

  1. ใน dataconnect/schema/schema.gql ให้เพิ่มช่อง descriptionEmbedding ลงในตาราง Movie โดยทำดังนี้
type Movie
  # The below parameter values are generated by default with @table, and can be edited manually.
  @table {
  # implicitly calls @col to generates a column name. ex: @col(name: "movie_id")
  id: UUID! @default(expr: "uuidV4()")
  title: String!
  imageUrl: String!
  releaseYear: Int
  genre: String
  rating: Float
  description: String
  tags: [String]
  descriptionEmbedding: Vector @col(size:768) # Enables vector search
}

สิ่งสำคัญที่เรียนรู้:

  • descriptionEmbedding: Vector @col(size:768): ช่องนี้จะจัดเก็บการฝังเชิงความหมายของคำอธิบายภาพยนตร์ ซึ่งช่วยให้ค้นหาเนื้อหาตามเวกเตอร์ในแอปได้

การเปิดใช้งาน Vertex AI

  1. ทําตามคําแนะนําเบื้องต้นเพื่อตั้งค่า Vertex AI API ด้วย Google Cloud ขั้นตอนนี้เป็นขั้นตอนสําคัญในการสนับสนุนฟังก์ชันการสร้างการฝังและเวกเตอร์การค้นหา
  2. ทำให้สคีมาใช้งานได้อีกครั้งเพื่อเปิดใช้งาน pgvector และการค้นหาเวกเตอร์โดยคลิก "ทำให้ใช้งานได้จริง" โดยใช้ส่วนขยาย Firebase Data Connect ใน VSCode

การป้อนข้อมูลฐานข้อมูลด้วยเนื้อหาที่ฝัง

  1. เปิดโฟลเดอร์ dataconnect ใน VSCode แล้วคลิกเรียกใช้(ในเครื่อง) ใน optional_vector_embed.gql เพื่อป้อนข้อมูลฐานข้อมูลด้วยข้อมูลการฝังสำหรับภาพยนตร์

b858da780f6ec103.png

เพิ่มคำค้นหาแบบเวกเตอร์

  1. ใน dataconnect/movie-connector/queries.gql ให้เพิ่มข้อความค้นหาต่อไปนี้เพื่อทำการค้นหาเวกเตอร์
# Search movie descriptions using L2 similarity with Vertex AI
query SearchMovieDescriptionUsingL2Similarity($query: String!)
@auth(level: PUBLIC) {
  movies_descriptionEmbedding_similarity(
    compare_embed: { model: "textembedding-gecko@003", text: $query }
    method: L2
    within: 2
    limit: 5
  ) {
    id
    title
    description
    tags
    rating
    imageUrl
  }
}

สรุปประเด็นสำคัญ:

  • compare_embed: ระบุรูปแบบการฝัง (textembedding-gecko@003) และข้อความอินพุต ($query) สำหรับการเปรียบเทียบ
  • method: ระบุวิธีการวัดความคล้ายคลึง (L2) ซึ่งแสดงถึงระยะทางแบบยูคลิด
  • within: จำกัดการค้นหาไว้ที่ภาพยนตร์ที่มีระยะ L2 ไม่เกิน 2 โดยเน้นที่เนื้อหาที่ตรงกันมาก
  • limit: จำกัดจำนวนผลลัพธ์ที่แสดงผลเป็น 5 รายการ

ใช้ฟังก์ชันการค้นหาเวกเตอร์ในแอป

  1. ใน app/src/lib/MovieService.ts ให้ยกเลิกการคอมเมนต์การนําเข้าต่อไปนี้

ใช้ฟังก์ชันการค้นหาเวกเตอร์ในแอป

เมื่อตั้งค่าสคีมาและคําค้นหาแล้ว ให้ผสานรวมการค้นหาเวกเตอร์เข้ากับเลเยอร์บริการของแอป ขั้นตอนนี้ช่วยให้คุณเรียกใช้คำค้นหาจากเว็บแอปได้

ใน app/src/lib/ MovieService.ts ให้ยกเลิกการคอมเมนต์การนําเข��าต่อไปนี้จาก SDK ซึ่งจะทํางานเหมือนกับการค้นหาอื่นๆ

import {
  searchMovieDescriptionUsingL2similarity,
  SearchMovieDescriptionUsingL2similarityData,
} from "@movie/dataconnect";

เพิ่มฟังก์ชันต่อไปนี้เพื่อผสานรวมการค้นหาที่อิงตามเวกเตอร์ไว้ในแอป

// Perform vector-based search for movies based on description
export const searchMoviesByDescription = async (
  query: string
): Promise<
  | SearchMovieDescriptionUsingL2similarityData["movies_descriptionEmbedding_similarity"]
  | null
> => {
  try {
    const response = await searchMovieDescriptionUsingL2similarity({ query });
    return response.data.movies_descriptionEmbedding_similarity;
  } catch (error) {
    console.error("Error fetching movie descriptions:", error);
    return null;
  }
};


สรุปประเด็นสำคัญ:

  • searchMoviesByDescription: ฟังก์ชันนี้จะเรียกคําค้นหา searchMovieDescriptionUsingL2similarity โดยส่งข้อความที่ป้อนเพื่อค้นหาเนื้อหาตามเวกเตอร์

ดูการใช้งานจริง

ไปที่ส่วน "การค้นหาเวกเตอร์" ในแถบนาบ และพิมพ์วลีอย่าง "โรแมนติกและทันสมัย" คุณจะเห็นรายการภาพยนตร์ที่ตรงกับเนื้อหาที่คุณค้นหา หรือไปที่หน้ารายละเอียดภาพยนตร์ของภาพยนตร์เรื่องใดก็ได้ แล้วดูส่วนภาพยนตร์ที่คล้ายกันซึ่งอยู่ด้านล่างของหน้า

7b71f1c75633c1be.png

11. บทสรุป

ยินดีด้วย คุณควรใช้เว็บแอปได้แล้ว หากต้องการเล่นกับข้อมูลภาพยนตร์ของคุณเอง ไม่ต้องกังวล เพียงแทรกข้อมูลของคุณเองโดยใช้ส่วนขยาย FDC โดยเลียนแบบไฟล์ _insert.gql หรือเพิ่มผ่านแผงการดำเนินการของ Data Connect

ดูข้อมูลเพิ่มเติม