1. לפני שמתחילים
ב-codelab הזה, תשולב 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 במודל של תשלום לפי שימוש
2. הגדרת סביבת הפיתוח
בשלב הזה של ה-codelab נסביר איך להגדיר את הסביבה כדי להתחיל לבנות את אפליקציית ביקורות הסרטים באמצעות Firebase Data Connect.
- משכפלים את מאגר הפרויקט ומתקינים את יחסי התלות הנדרשים:
git clone https://github.com/firebaseextended/codelab-dataconnect-web cd codelab-dataconnect-web cd ./app && npm i npm run dev
- אחרי שמריצים את הפקודות האלה, פותחים את http://localhost:5173 בדפדפן כדי לראות את אפליקציית האינטרנט שפועלת באופן מקומי. הוא ישמש כחלק הקדמי של אפליקציית ביקורת הסרטים, ותוכלו ליצור אינטראקציה עם התכונות שלו.
- פותחים את התיקייה המשוכפלת
codelab-dataconnect-web
באמצעות Visual Studio Code. כאן מגדירים את הסכימה, כותבים שאילתות ובודקים את הפונקציונליות של האפליקציה. - כדי להשתמש בתכונות של Data Connect, צריך להתקין את התוסף Firebase Data Connect Visual Studio Extension.
אפשר גם להתקין את התוסף מ-Visual Studio Code Marketplace או לחפש אותו ב-VS Code. - פותחים פרויקט Firebase קיים או יוצרים פרויקט חדש במסוף Firebase.
- מקשרים את פרויקט Firebase לתוסף Firebase Data Connect ל-VSCode. בתוסף, מבצעים את הפעולות הבאות:
- לוחצים על הלחצן כניסה.
- לוחצים על Connect a Firebase Project (קישור פרויקט Firebase) ובוחרים את פרויקט Firebase.
- מפעילים את האמולטורים של Firebase באמצעות התוסף Firebase Data Connect ל-VS Code:
לוחצים על Start Emulators (הפעלת אמולטורים) ומוודאים שהאמולטורים פועלים במסוף.
3. בדיקת בסיס הקוד הראשוני
בקטע הזה נסביר על אזורים מרכזיים בבסיס הקוד של האפליקציה. למרות שחסרות באפליקציה פונקציות מסוימות, היא עוזרת להבין את המבנה הכללי.
מבנה התיקיות והקבצים
בקטעי המשנה הבאים מופיעה סקירה כללית של מבנה התיקיות והקבצים באפליקציה.
הספרייה 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 בפרויקט Firebase. -
lib/dataconnect-sdk/
: מכיל את ה-SDK שנוצר. אפשר לערוך את המיקום של יצירת ה-SDK בקובץconnector/connector.yaml
, והמערכת תיצור באופן אוטומטי קובצי SDK בכל פעם שתגדירו שאילתה או מוטציה.
4. הגדרת סכימה לביקורות על סרטים
בקטע הזה, תגדירו בסכימה את המבנה ואת קשרי הגומלין בין הישויות העיקריות באפליקציית הסרטים. יש מיפוי של ישויות כמו Movie
, User
, Actor
ו-Review
לטבלאות במסד הנתונים, והקשרים ביניהן מוגדרים באמצעות Firebase Data Connect והוראות סכימה של GraphQL. אחרי שהיא תוטמע, האפליקציה תהיה מוכנה לטפל בכל דבר, החל מחיפוש סרטים עם דירוג גבוה וסינון לפי ז'אנר, ועד לאפשרות למשתמשים לכתוב ביקורות, לסמן פריטים כמועדפים, לעיין בסרטים דומים או למצוא סרטים מומלצים על סמך קלט טקסט באמצעות חיפוש וקטורי.
ישויות וקשרים מרכזיים
הסוג Movie
מכיל פרטים חשובים כמו שם, ז'אנר ותגים, שהאפליקציה משתמשת בהם לחיפושים ולפרופילים של סרטים. הסוג User
עוקב אחרי אינטראקציות של משתמשים, כמו ביקורות ומועדפים. Reviews
לקשר משתמשים לסרטים, ולאפשר לאפליקציה להציג דירוגים ומשוב שנוצרו על ידי משתמשים.
הקשרים בין סרטים, שחקנים ומשתמשים הופכים את האפליקציה לדינמית יותר. הטבלה MovieActor
join עוזרת להציג פרטים על צוות השחקנים ופילמוגרפיות של שחקנים. הסוג FavoriteMovie
מאפשר למשתמשים להוסיף סרטים למועדפים, כדי שהאפליקציה תוכל להציג רשימת מועדפים בהתאמה אישית ולהדגיש בחירות פופולריות.
הגדרה של הטבלה Movie
הסוג Movie
מגדיר את המבנה הראשי של ישות מסוג סרט, כולל שדות כמו title
, genre
, releaseYear
ו-rating
.
מעתיקים ומדביקים את קטע הקוד בקובץ 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
יוצר קשר גומלין של אחד לאחד עם הסוג 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
}
נקודות עיקריות:
- סרט! @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
המאפיין User
type מגדיר ישות משתמש שמבצעת אינטראקציה עם סרטים על ידי כתיבת ביקורות או הוספת סרטים למועדפים.
מעתיקים ומדביקים את קטע הקוד בקובץ dataconnect/schema/schema.gql
:
type User
@table {
id: String! @col
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, יוצר באופן מרומז מפתח זר
movieId: UUID!
. - user: מפנה לסוג המשתמש, ויוצר באופן מרומז מפתח זר
userId: UUID!
.
הגדרה של הטבלה Review
הסוג Review
מייצג את ישות הביקורת ומקשר בין הסוגים User
ו-Movie
בקשר של רבים לרבים (משתמש אחד יכול לכתוב הרבה ביקורות, ולכל סרט יכולות להיות הרבה ביקורות).
מעתיקים ומדביקים את קטע הקוד בקובץ 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: הפניה למשתמש שכתב את הביקורת.
- סרט: הפניה לסרט שעליו נכתבת הביקורת.
- reviewDate: מוגדר אוטומטית לזמן שבו הביקורת נוצרה באמצעות
@default(expr: "request.time")
.
שדות שנוצרים אוטומטית וערכי ברירת מחדל
הסכימה משתמשת בביטויים כמו @default(expr: "uuidV4()")
כדי ליצור באופן אוטומטי מזהים ייחודיים וחותמות זמן. לדוגמה, השדה id
בסוגים Movie
ו-Review
מתמלא אוטומטית במזהה ייחודי אוניברסלי (UUID) כשנוצר רשומה חדשה.
עכשיו, אחרי שהגדרתם את הסכימה, לאפליקציה שלכם לצפייה בסרטים יש בסיס מוצק למבנה הנתונים וליחסים בין הנתונים.
5. אחזור של הסרטים המובילים והחדשים ביותר
בקטע הזה, תוסיפו נתונים פיקטיביים של סרטים לאמולטורים המקומיים, ואז תטמיעו את המחברים (שאילתות) ואת קוד TypeScript כדי לקרוא למחברים האלה באפליקציית האינטרנט. בסיום, האפליקציה תוכל לאחזר ולהציג באופן דינמי את הסרטים החדשים והפופולריים ביותר ישירות מהמסד הנתונים.
הוספת נתונים לדוגמה של סרט, שחקן וביקורת
- ב-VSCode, פותחים את
dataconnect/moviedata_insert.gql
. מוודאים שהאמולטורים בתוסף Firebase Data Connect פועלים. - בצד העליון של הקובץ אמור להופיע לחצן Run (local). לוחצים על האפשרות הזו כדי להוסיף את נתוני הסרט לדוגמה למסד הנתונים.
- בודקים את מסוף הפעלת Data Connect כדי לוודא שהנתונים נוספו בהצלחה.
הטמעת המחבר
- פתיחת
dataconnect/movie-connector/queries.gql
. תוכלו למצוא שאילתתListMovies
בסיסית בתגובות: השאילתה הזו מאחזרת את כל הסרטים ואת הפרטים שלהם (לדוגמה,query ListMovies @auth(level: PUBLIC) { movies { id title imageUrl releaseYear genre rating tags description } }
id
, title
, releaseYear
). עם זאת, היא לא ממיינת את הסרטים. - מחליפים את שאילתת
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 } }
- לוחצים על הלחצן Run (local) (הפעלה (מקומית)) כדי להריץ את השאילתה על מסד הנתונים המקומי. אפשר גם להזין את משתני השאילתה בחלונית ההגדרות לפני ההפעלה.
נקודות עיקריות:
-
movies()
: שדה שאילתת GraphQL לשליפת נתוני סרטים ממסד הנתונים. -
orderByRating
: פרמטר למיון סרטים לפי דירוג (סדר עולה או סדר יורד). -
orderByReleaseYear
: פרמטר למיון סרטים לפי שנת היציאה לאקרנים (עולה/יורד). -
limit
: מגבילה את מספר הסרטים שמוחזרים.
שילוב שאילתות באפליקציית האינטרנט
בחלק הזה של ה-codelab, תשתמשו בשאילתות שהוגדרו בקטע הקודם באפליקציית האינטרנט. האמולטורים של Firebase Data Connect יוצרים ערכות SDK על סמך המידע בקובצי .gql
(במיוחד schema.gql
, queries.gql
, mutations.gql
) ובקובץ connector.yaml
. אפשר להפעיל את ה-SDK האלה ישירות באפליקציה.
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מסירים את ההערה מהצהרת הייבוא בחלק העליון: הפונקציהimport { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";
listMovies
, סוג התגובהListMoviesData
וה-enumOrderDirection
הם כולם ערכות SDK שנוצרו על ידי האמולטורים של Firebase Data Connect על סמך הסכימה והשאילתות שהגדרתם קודם . - מחליפים את הפונקציות
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 הסרטים המובילים והסרטים החדשים בדף הבית של האפליקציה.
הדגמה
טוענים מחדש את אפליקציית האינטרנט כדי לראות את השאילתה בפעולה. עכשיו דף הבית מציג באופן דינמי את רשימת הסרטים, והנתונים נשלפים ישירות מהמסד הנתונים המקומי. יוצגו לכם הסרטים החדשים והסרטים עם הדירוג הכי גבוה, בהתאם לנתונים שהגדרתם.
6. הצגת פרטים על סרטים ושחקנים
בקטע הזה נטמיע את הפונקציונליות לאחזור מידע מפורט על סרט או על שחקן באמצעות המזהים הייחודיים שלהם. התהליך הזה כולל לא רק אחזור נתונים מהטבלאות המתאימות, אלא גם צירוף של טבלאות קשורות כדי להציג פרטים מקיפים, כמו ביקורות על סרטים ופילמוגרפיה של שחקנים.
הטמעה של מחברים
- פותחים את
dataconnect/movie-connector/queries.gql
בפרויקט. - מוסיפים את השאילתות הבאות כדי לאחזר פרטים על סרטים ושחקנים:
# 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 } } }
- שומרים את השינויים ובודקים את השאילתות.
נקודות עיקריות:
-
movie()
/actor()
: שדות של שאילתת GraphQL לאחזור של סרט או שחקן יחיד מהטבלהMovies
אוActors
. -
_on_
: מאפשר גישה ישירה לשדות מסוג משויך שיש לו קשר של מפתח זר. לדוגמה,reviews_on_movie
מאחזר את כל הביקורות שקשורות לסרט מסוים. -
_via_
: משמש לניווט בין קשרים מסוג רבים לרבים באמצעות טבלת איחוד. לדוגמה,actors_via_MovieActor
ניגש לסוגActor
דרך טבלת הצירוףMovieActor
, והתנאיwhere
מסנן שחקנים על סמך התפקיד שלהם (לדוגמה, 'ראשי' או 'משני').
בדיקת השאילתה באמצעות הזנת נתונים מדומים
- בחלונית ההרצה של Data Connect, אפשר לבדוק את השאילתה על ידי הזנת מזהים מדומים, כמו:
{"id": "550e8400-e29b-41d4-a716-446655440000"}
- לוחצים על Run (local) (הפעלה (מקומית)) עבור
GetMovieById
כדי לאחזר את הפרטים על הסרט "Quantum Paradox" (הסרט הדמיוני שאליו מתייחס המזהה שלמעלה).
שילוב שאילתות באפליקציית האינטרנט
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מסירים את ההערה מהייבוא הבא:import { getMovieById, GetMovieByIdData } from "@movie/dataconnect"; import { GetActorByIdData, getActorById } from "@movie/dataconnect";
- מחליפים את הפונקציות
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
: אלה סוגי התוצאות שמשמשים להצגת פרטים על סרטים ושחקנים באפליקציה.
הדגמה
עכשיו עוברים לדף הבית של אפליקציית האינטרנט. אפשר ללחוץ על סרט כדי לראות את כל הפרטים שלו, כולל השחקנים והביקורות – מידע שנלקח מטבלאות קשורות. באופן דומה, לחיצה על שחקן תציג את הסרטים שבהם הוא השתתף.
7. טיפול באימות משתמשים
בקטע הזה נטמיע פונקציונליות של כניסה ויציאה של משתמשים באמצעות אימות ב-Firebase. בנוסף, תוכלו להשתמש בנתוני האימות של Firebase כדי לאחזר או להוסיף נתוני משתמשים ישירות ב-Firebase DataConnect, וכך להבטיח ניהול מאובטח של משתמשים באפליקציה.
הטמעה של מחברים
- פתיחת
mutations.gql
ב-dataconnect/movie-connector/
. - מוסיפים את המוטציה הבאה כדי ליצור או לעדכן את המשתמש הנוכחי שעבר אימות:
# 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, ולא על ידי המשתמש או האפליקציה. כך נוסף עוד שכבת אבטחה שמבטיחה שהטיפול במזהה המשתמש יהיה מאובטח ואוטומטי.
אחזור המשתמש הנוכחי
- פתיחת
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
: מאחזר את כל הביקורות שקשורות למשתמש, כוללid
ו-title
של הסרט. -
favorite_movies_on_user
: מאחזר את כל הסרטים שסומנו כמועדפים על ידי המשתמש, כולל מידע מפורט כמוgenre
,releaseYear
,rating
ו-metadata
.
-
שילוב שאילתות באפליקציית האינטרנט
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מבטלים את ההערה של שורות הייבוא הבאות:import { upsertUser } from "@movie/dataconnect"; import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
- מחליפים את הפונקציות
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
: הפונקציה הזו מאזינה לשינויים בסטטוס האימות. כשמשתמש נכנס לחשבון, המערכת מגדירה את הנתונים של המשתמש ומבצעת קריאה ל-mutationupsertUser
כדי ליצור או לעדכן את פרטי המשתמש במסד הנתונים. -
handleGetCurrentUser
: מאחזר את הפרופיל של המשתמש הנוכחי באמצעות השאילתהgetCurrentUser
, שמאחזרת את הביקורות של המשתמש ואת הסרטים המועדפים עליו.
הדגמה
עכשיו לוחצים על הלחצן 'כניסה באמצעות חשבון Google' בסרגל הניווט. אפשר להיכנס באמצעות האמולטור של Firebase Authentication. אחרי הכניסה לחשבון, לוחצים על 'הפרופיל שלי'. בשלב הזה הוא יהיה ריק, אבל הגדרתם את הבסיס לטיפול בנתונים ספציפיים למשתמש באפליקציה.
8. הטמעה של אינטראקציות של משתמשים
בקטע הזה של ה-codelab, תטמיעו אינטראקציות עם משתמשים באפליקציה של ביקורות על סרטים, ובאופן ספציפי תאפשרו למשתמשים לנהל את הסרטים המועדפים שלהם ולכתוב או למחוק ביקורות.
איך מאפשרים למשתמש להוסיף סרט למועדפים
בקטע הזה תגדירו את מסד הנתונים כך שהמשתמשים יוכלו להוסיף סרט למועדפים.
הטמעה של מחברים
- פתיחת
mutations.gql
ב-dataconnect/movie-connector/
. - מוסיפים את המוטציות הבאות כדי לטפל בהוספת סרטים למועדפים:
# 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, כדי להבטיח שרק משתמשים מאומתים יוכלו לגשת לנתונים או לשנות אותם.
איך בודקים אם סרט מסוים סומן כמועדף
- פתיחת
queries.gql
ב-dataconnect/movie-connector/
. - מוסיפים את השאילתה הבאה כדי לבדוק אם סרט מסוים נוסף למועדפים:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { movieId } }
נקודות עיקריות:
-
auth.uid
: מאפשר גישה מאובטחת לנתונים ספציפיים למשתמש באמצעות אימות ב-Firebase. -
favorite_movie
: בודק אתfavorite_movies
join table כדי לראות אם סרט מסוים מסומן כמועדף על ידי המשתמש הנוכחי.
שילוב שאילתות באפליקציית האינטרנט
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מסירים את ההערה מהייבוא הבא:import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
- מחליפים את הפונקציות
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
כדי לבדוק אם סרט מסוים מסומן כמועדף על ידי המשתמש.
הדגמה
עכשיו אפשר להוסיף סרטים למועדפים או להסיר אותם מהמועדפים בלחיצה על סמל הלב בכרטיסי הסרטים ובדף פרטי הסרט. בנוסף, תוכלו לראות את הסרטים האהובים עליכם בדף הפרופיל.
איך משתמשים יכולים להוסיף או למחוק ביקורות
לאחר מכן, מטמיעים באפליקציה את הקטע לניהול ביקורות משתמשים.
הטמעה של מחברים
ב-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, כך שאין צורך להזין אותו ידנית.
שילוב שאילתות באפליקציית האינטרנט
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מסירים את ההערה מהייבוא הבא:import { addReview, deleteReview } from "@movie/dataconnect";
- מחליפים את הפונקציות
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
mutation כדי להוסיף ביקורת על הסרט שצוין, ומקשר אותה בצורה מאובטחת למשתמש המאומת. -
handleDeleteReview
: משתמש במוטציהdeleteReview
כדי להסיר ביקורת על סרט שכתב המשתמש המאומת.
הדגמה
עכשיו המשתמשים יכולים להשאיר ביקורות על סרטים בדף הפרטים של הסרט. הם יכולים גם לראות ולמחוק את הביקורות שלהם בדף הפרופיל, כך שיש להם שליטה מלאה באינטראקציות שלהם עם האפליקציה.
9. מסננים מתקדמים והתאמה חלקית של טקסט
בקטע הזה נטמיע יכולות חיפוש מתקדמות, שיאפשרו למשתמשים לחפש סרטים לפי טווח של דירוגים ושנות יציאה לאקרנים, לסנן לפי ז'אנרים ותגים, לבצע התאמה חלקית של טקסט בכותרות או בתיאורים, ואפילו לשלב כמה מסננים כדי לקבל תוצאות מדויקות יותר.
הטמעה של מחברים
- פתיחת
queries.gql
ב-dataconnect/movie-connector/
- מוסיפים את השאילתה הבאה כדי לתמוך ביכולות חיפוש שונות:
# 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
clause: מציין את התנאים לסינון הנתונים. בכל קטע (סרטים, שחקנים, ביקורות) נעשה שימוש בסעיףwhere
כדי להגדיר את הקריטריונים הספציפיים לחיפוש.
שילוב שאילתות באפליקציית האינטרנט
- ב-
MovieService
(app/src/lib/MovieService.tsx
), מסירים את ההערה מהייבוא הבא:import { searchAll, SearchAllData } from "@movie/dataconnect";
- מחליפים את הפונקציה
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
כדי לבצע חיפוש על סמך הקלט של המשתמש, ולסנן את התוצאות לפי פרמטרים כמו שנה, דירוג, ז'אנר והתאמות חלקיות של טקסט.
הדגמה
עוברים לדף 'חיפוש מתקדם' מסרגל הניווט באפליקציית האינטרנט. עכשיו אפשר לחפש סרטים, שחקנים וביקורות באמצעות מסננים וקלט שונים, ולקבל תוצאות חיפוש מפורטות ומותאמות אישית.
10. אופציונלי: פריסה ב-Cloud (נדרש חיוב)
אחרי שסיימתם את האיטרציה של הפיתוח המקומי, הגיע הזמן לפרוס את הסכימה, הנתונים והשאילתות בשרת. אפשר לעשות את זה באמצעות התוסף Firebase Data Connect ל-VS Code או Firebase CLI.
שדרוג תוכנית התמחור של Firebase
כדי לשלב את Firebase Data Connect עם Cloud SQL for PostgreSQL, הפרויקט ב-Firebase צריך להיות במסגרת תוכנית התמחור 'תשלום לפי שימוש' (Blaze), כלומר הוא צריך להיות מקושר לחשבון לחיוב ב-Cloud.
- בחשבון לחיוב ב-Cloud צריך להגדיר אמצעי תשלום, כמו כרטיס אשראי.
- אם אתם חדשים ב-Firebase וב-Google Cloud, כדאי לבדוק אם אתם עומדים בדרישות לקבלת קרדיט בסך 300$וחשבון לחיוב ב-Cloud עם תקופת ניסיון בחינם.
- אם אתם משתתפים בסדנת קוד כחלק מאירוע, כדאי לשאול את מארגן האירוע אם יש קרדיטים ל-Cloud.
כדי לשדרג את הפרויקט לתוכנית Blaze, פועלים לפי השלבים הבאים:
- במסוף Firebase, בוחרים באפשרות שדרוג התוכנית.
- בוחרים בתוכנית Blaze. פועלים לפי ההוראות במסך כדי לקשר חשבון לחיוב ב-Cloud לפרויקט.
אם הייתם צריכים ליצור חשבון לחיוב ב-Cloud כחלק מהשדרוג, יכול להיות שתצטרכו לחזור לתהליך השדרוג במסוף Firebase כדי להשלים את השדרוג.
קישור אפליקציית האינטרנט לפרויקט Firebase
- רושמים את אפליקציית האינטרנט בפרויקט Firebase באמצעות מסוף Firebase:
- פותחים את הפרויקט ולוחצים על Add App (הוספת אפליקציה).
- בינתיים אפשר להתעלם מהגדרת ה-SDK ומהגדרת ההגדרות, אבל חשוב להעתיק את אובייקט
firebaseConfig
שנוצר.
- מחליפים את הערך הקיים
firebaseConfig
ב-app/src/lib/firebase.tsx
בתצורה שהעתקתם ממסוף Firebase.const firebaseConfig = { apiKey: "API_KEY", authDomain: "PROJECT_ID.firebaseapp.com", projectId: "PROJECT_ID", storageBucket: "PROJECT_ID.firebasestorage.app", messagingSenderId: "SENDER_ID", appId: "APP_ID" };
- יצירת אפליקציית האינטרנט: חוזרים ל-VS Code, בתיקייה
app
, ומשתמשים ב-Vite כדי ליצור את אפליקציית האינטרנט לפריסה באירוח:cd app npm run build
הגדרת Firebase Authentication בפרויקט Firebase
- מגדירים אימות ב-Firebase באמצעות כניסה לחשבון Google.
- (אופציונלי) מאפשרים דומיינים לאימות ב-Firebase באמצעות מסוף Firebase (לדוגמה,
http://127.0.0.1
).- בהגדרות אימות, עוברים אל דומיינים מורשים.
- לוחצים על 'הוספת דומיין' ומוסיפים את הדומיין המקומי לרשימה.
פריסה באמצעות Firebase CLI
- ב-
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"]
- מוודאים שהגדרתם את Firebase CLI עם הפרויקט:
npm i -g firebase-tools firebase login --reauth firebase use --add
- בטרמינל, מריצים את הפקודה הבאה כדי לפרוס:
firebase deploy --only dataconnect,hosting
- מריצים את הפקודה הבאה כדי להשוות את השינויים בסכימה:
firebase dataconnect:sql:diff
- אם השינויים מקובלים, אפשר להחיל אותם באמצעות הפקודה:
firebase dataconnect:sql:migrate
המכונה שלכם ב-Cloud SQL ל-PostgreSQL תעודכן עם הסכימה והנתונים הסופיים שנפרסו. אפשר לעקוב אחרי הסטטוס במסוף Firebase.
עכשיו אמורה להיות לכם אפשרות לראות את האפליקציה בשידור חי בכתובת your-project.web.app/
. בנוסף, אפשר ללחוץ על הפעלה (סביבת ייצור) בחלונית Firebase Data Connect, בדיוק כמו שעשיתם עם האמולטורים המקומיים, כדי להוסיף נתונים לסביבת הייצור.
11. אופציונלי: חיפוש וקטורי באמצעות Firebase Data Connect (נדרש חיוב)
בקטע הזה נסביר איך להפעיל חיפוש וקטורי באפליקציה לביקורת סרטים באמצעות Firebase Data Connect. התכונה הזו מאפשרת לבצע חיפושים שמבוססים על תוכן, כמו חיפוש סרטים עם תיאורים דומים באמצעות הטמעות וקטוריות.
כדי לבצע את השלב הזה, צריך להשלים את השלב הקודם ב-codelab הזה כדי לפרוס ל-Google Cloud.
עדכון הסכימה כך שתכלול הטמעות של שדה
ב-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
- פועלים לפי מדריך הדרישות המוקדמות כדי להגדיר את ממשקי Vertex AI API מ-Google Cloud. השלב הזה חיוני כדי לתמוך בהטמעה של יצירת וקטורים ובפונקציונליות של חיפוש וקטורים.
- מבצעים פריסה מחדש של הסכימה כדי להפעיל את
pgvector
ואת חיפוש הווקטורים. לשם כך, לוחצים על 'פריסה בסביבת הייצור' באמצעות התוסף Firebase Data Connect ל-VS Code.
איכלוס מסד הנתונים בהטמעות
- פותחים את התיקייה
dataconnect
ב-VS Code. - לוחצים על Run(local) (הפעלה (מקומית)) ב-
optional_vector_embed.gql
כדי לאכלס את מסד הנתונים בהטמעות של הסרטים.
הוספת שאילתת חיפוש וקטורי
ב-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.
הטמעת הפונקציה של חיפוש וקטורי באפליקציה
אחרי שמגדירים את הסכימה והשאילתה, משלבים את החיפוש הווקטורי בשכבת השירות של האפליקציה. בשלב הזה תוכלו לקרוא לשאילתת החיפוש מאפליקציית האינטרנט שלכם.
- ב-
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
, מעבירה את טקסט הקלט כדי לבצע חיפוש תוכן מבוסס-וקטור.
הדגמה
עוברים לקטע Vector Search (חיפוש וקטורי) בסרגל הניווט ומקלידים משפטים כמו romantic and modern (רומנטי ומודרני). תוכלו לראות רשימה של סרטים שתואמים לתוכן שחיפשתם, או להיכנס לדף הפרטים של סרט כלשהו ולעיין בקטע'סרטים דומים' בתחתית הדף.
12. סיכום
כל הכבוד, עכשיו אפשר להשתמש באפליקציית האינטרנט. אם רוצים להתנסות עם נתוני סרטים משלכם, אפשר להוסיף אותם באמצעות התוסף Firebase Data Connect. כדי לעשות את זה, צריך לחקות את _insert.gql
הקבצים או להוסיף אותם דרך חלונית ההפעלה של Data Connect ב-VS Code.