1. לפני שמתחילים
בקודלאב הזה תלמדו לשלב את 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 Code
- התקנה של Node.js באמצעות nvm-windows (Windows) או nvm (macOS/Linux)
- אם עדיין לא עשיתם זאת, יוצרים פרויקט ב-Firebase במסוף Firebase.
- (אופציונלי) לחיפוש וקטורים, משדרגים את הפרויקט לתוכנית התמחור Blaze בתשלום לפי שימוש
2. הגדרת סביבת הפיתוח
בשלב הזה של הקודלאב נסביר איך מגדירים את הסביבה כדי להתחיל לפתח את אפליקציית ביקורות הסרטים באמצעות 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, צריך להתקין את תוסף Visual Studio של Firebase Data Connect.
לחלופין, אפשר להתקין את התוסף מ-Visual Studio Code Marketplace או לחפש אותו ב-VS Code. - פותחים או יוצרים פרויקט Firebase חדש במסוף Firebase.
- מקשרים את פרויקט Firebase לתוסף VSCode של Firebase Data Connect. בתוסף, מבצעים את הפעולות הבאות:
- לוחצים על הלחצן Sign in.
- לוחצים על קישור פרויקט Firebase ובוחרים את פרויקט Firebase.
- מפעילים את המהדמנים של Firebase באמצעות התוסף Firebase Data Connect ל-VS Code:
לוחצים על Start Emulators (הפעלת המהדמנים) ומוודאים שהמהדמנים פועלים במסוף.
3. בדיקת קוד המקור של ה-starter
בקטע הזה נסקור תחומים מרכזיים בקוד המקור של ערכת ההתחלה של האפליקציה. באפליקציה חסרות פונקציות מסוימות, אבל כדאי להבין את המבנה הכללי שלה.
מבנה התיקיות והקבצים
בקטעים המשניים הבאים מוצגת סקירה כללית של מבנה התיקיות והקבצים של האפליקציה.
הספרייה dataconnect/
מכיל הגדרות של Firebase Data Connect, מחברים (שמגדירים שאילתות ומוטציות) וקובצי סכימה.
schema/schema.gql
: הגדרת הסכימה של GraphQLconnector/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
, ו-SDKs ייווצרו באופן אוטומטי בכל פעם שתגדירו שאילתה או מוטציה.
4. הגדרת סכימה לביקורות על סרטים
בקטע הזה מגדירים את המבנה ואת היחסים בין ישויות המפתח באפליקציית הסרטים בסכימה. ישויות כמו Movie
, User
, Actor
ו-Review
ממפות לטבלאות של מסדי נתונים, והיחסים נוצרים באמצעות Firebase Data Connect והוראות הסכימה של GraphQL. אחרי שתגדירו את הרכיב, האפליקציה תהיה מוכנה לטפל בכל דבר, החל מחיפוש סרטים עם הדירוג הגבוה ביותר וסינון לפי ז'אנר, ועד לאפשרות של המשתמשים לכתוב ביקורות, לסמן פריטים כ'מועדפים', לבחון סרטים דומים או למצוא סרטים מומלצים על סמך קלט טקסט באמצעות חיפוש וקטורים.
ישויות ויחסים מרכזיים
הסוג Movie
מכיל פרטים חשובים כמו כותרת, ז'אנר ותגים, שהאפליקציה משתמשת בהם בחיפושים ובפרופילים של סרטים. הסוג User
עוקב אחרי אינטראקציות של משתמשים, כמו ביקורות ומועדפים. Reviews
לקשר משתמשים לסרטים, ולאפשר לאפליקציה להציג דירוגים ומשוב שנוצרו על ידי משתמשים.
הקשרים בין סרטים, שחקנים ומשתמשים הופכים את האפליקציה לדינמית יותר. טבלת המיזוג MovieActor
עוזרת להציג את פרטי השחקנים ואת הפילמוגרפיות שלהם. הסוג 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: הגדרת התפקיד של השחקן בסרט (למשל, 'עיקרי' או 'תומך').
הגדרת הטבלה User
הסוג 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!
.
הגדרת הטבלה 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: הפניה למשתמש שהשאיר את הביקורת.
- movie: הפניה לסרט שעליו נכתבת הביקורת.
- reviewDate: מוגדר באופן אוטומטי לזמן שבו הבדיקה נוצרה באמצעות
@default(expr: "request.time")
.
שדות שמוגדרים כברירת מחדל ושדות שנוצרים באופן אוטומטי
בסכימה נעשה שימוש בביטויים כמו @default(expr: "uuidV4()")
כדי ליצור באופן אוטומטי מזהים ייחודיים חותמות זמן. לדוגמה, השדה id
בסוגי Movie
ו-Review
מאוכלס באופן אוטומטי ב-UUID כשיוצרים רשומה חדשה.
עכשיו, אחרי שהגדרתם את הסכימה, לאפליקציית הסרטים יש בסיס יציב למבנה הנתונים וליחסים שלה.
5. אחזור הסרטים המובילים והחדשים ביותר
בקטע הזה תוסיפו נתוני סרטים מדומים למהדמרים המקומיים, ולאחר מכן תטמיעו את המחברים (שאילתות) ואת קוד TypeScript כדי לבצע קריאה למחברים האלה באפליקציית האינטרנט. בסיום, האפליקציה תוכל לאחזר באופן דינמי ולהציג את הסרטים החדשים והמובילים בדירוג ישירות ממסד הנתונים.
הוספת נתונים מדומים של סרטים, שחקנים וביקורות
- ב-VSCode, פותחים את
dataconnect/moviedata_insert.gql
. מוודאים שהמעבדים בסימולטורים של התוסף Firebase Data Connect פועלים. - בחלק העליון של הקובץ אמור להופיע הלחצן הפעלה (מקומית). לוחצים עליו כדי להוסיף את נתוני הסרט המדומה למסד הנתונים.
- בודקים את מסוף Data Connect Execution כדי לוודא שהנתונים נוספו בהצלחה.
הטמעת המחבר
- פתיחת
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
: הגבלת מספר הסרטים שיתקבלו בתוצאה.
שילוב שאילתות באפליקציית האינטרנט
בקטע הזה של הקודלאב, תשתמשו בשאילתות שהוגדרו בקטע הקודם באפליקציית האינטרנט. המהדמנים של 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"}
- לוחצים על הפעלה (מקומית) עבור
GetMovieById
כדי לאחזר את הפרטים על 'פרדוקס קוונטי' (סרט ההדמיה שהמזהה שלמעלה קשור אליו).
שילוב שאילתות באפליקציית האינטרנט
- בקובץ
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
: הפונקציה הזו מקשיבה לשינויים במצב האימות. כשמשתמש נכנס לחשבון, המערכת מגדירה את הנתונים של המשתמש ומפעילה את המוטציהupsertUser
כדי ליצור או לעדכן את פרטי המשתמש במסד הנתונים.handleGetCurrentUser
: אחזור הפרופיל של המשתמש הנוכחי באמצעות השאילתהgetCurrentUser
, שמאחזרת את הביקורות והסרטים האהובים על המשתמש.
הדגמה
עכשיו לוחצים על הלחצן 'כניסה באמצעות חשבון Google' בסרגל הניווט. אפשר להיכנס באמצעות אמולטור האימות של Firebase. אחרי הכניסה לחשבון, לוחצים על 'הפרופיל שלי'. בשלב הזה הוא יהיה ריק, אבל עכשיו כבר הגדרתם את הבסיס לטיפול בנתונים ספציפיים למשתמש באפליקציה.
8. הטמעת אינטראקציות של משתמשים
בקטע הזה של הקודלה, נתכנן אינטראקציות של משתמשים באפליקציית ביקורות הסרטים, במיוחד כדי לאפשר למשתמשים לנהל את הסרטים האהובים עליהם ולכתוב או למחוק ביקורות.
איך מאפשרים למשתמש להוסיף סרט למועדפים
בקטע הזה מגדירים את מסד הנתונים כך שמשתמשים יוכלו להוסיף סרט למועדפים.
הטמעת מחברים
- פותחים את
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
כדי לראות אם סרט ספציפי מסומן כמועדף על ידי המשתמש הנוכחי.
שילוב שאילתות באפליקציית האינטרנט
- בקובץ
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
כדי להוסיף ביקורת על הסרט שצוין, ולקשר אותה בצורה מאובטחת למשתמש המאומת.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
: מציין את התנאים לסינון הנתונים. בכל קטע (סרטים, שחקנים, ביקורות) נעשה שימוש בפסקה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 או באמצעות ה-CLI של Firebase.
שדרוג של תוכנית התמחור ב-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 בפרויקט Firebase
- מגדירים אימות ב-Firebase באמצעות כניסה באמצעות חשבון Google.
- (אופציונלי) מאפשרים דומיינים לאימות ב-Firebase באמצעות מסוף Firebase (לדוגמה,
http://127.0.0.1
).- בהגדרות של Authentication, עוברים אל Authorized Domains.
- לוחצים על 'הוספת דומיין' וכוללים את הדומיין המקומי ברשימה.
פריסה באמצעות 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 for PostgreSQL תתעדכן בנתונים ובסכימה הסופיים שנפרסו. אפשר לעקוב אחרי הסטטוס במסוף Firebase.
עכשיו אמורה להופיע האפליקציה שלך ב-your-project.web.app/
. בנוסף, אפשר ללחוץ על הפעלה (ייצור) בחלונית של Firebase Data Connect, בדיוק כמו שעשיתם עם המהדמנים המקומיים, כדי להוסיף נתונים לסביבת הייצור.
11. אופציונלי: חיפוש וקטורים באמצעות Firebase Data Connect (נדרש חיוב)
בקטע הזה מפעילים חיפוש וקטורים באפליקציה של ביקורות על סרטים באמצעות Firebase Data Connect. התכונה הזו מאפשרת לבצע חיפושים מבוססי-תוכן, כמו חיפוש סרטים עם תיאורים דומים באמצעות הטמעת וקטורים.
כדי לבצע את השלב הזה, צריך להשלים את השלב האחרון של הקודלאב הזה לפריסה ב-Google Cloud.
עדכון הסכימה כך שתכלול הטמעות (embeddings) לשדה
ב-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.
איכלוס מסד הנתונים ב-embeddings
- פותחים את התיקייה
dataconnect
ב-VS Code. - לוחצים על Run(local) ב-
optional_vector_embed.gql
כדי לאכלס את מסד הנתונים ב-embeddings של הסרטים.
הוספת שאילתה לחיפוש וקטור
כדי לבצע חיפושים של וקטורים, מוסיפים את השאילתה הבאה לקובץ 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
ומעבירה את טקסט הקלט כדי לבצע חיפוש תוכן מבוסס-וקטור.
הדגמה
עוברים לקטע 'חיפוש וקטור' בסרגל הניווט ומקלידים ביטויים כמו 'רומנטי ומודרני'. תוצג רשימה של סרטים שתואמים לתוכן שאתם מחפשים. לחלופין, תוכלו להיכנס לדף הפרטים של סרט כלשהו ולבדוק את הקטע'סרטים דומים' שבתחתית הדף.
12. סיכום
מעולה, עכשיו אמורה להיות לך אפשרות להשתמש באפליקציית האינטרנט. אם אתם רוצים לשחק עם נתוני סרטים משלכם, אל דאגה, תוכלו להוסיף נתונים משלכם באמצעות התוסף Firebase Data Connect, על ידי חיקוי של קובצי _insert.gql
, או להוסיף אותם באמצעות חלונית הביצוע של Data Connect ב-VS Code.