1. Prima di iniziare
In questo codelab, integrerai Firebase Data Connect con un database Cloud SQL per creare un'app web di recensioni di film. L'app completata mostra come Firebase Data Connect semplifica il processo di creazione di applicazioni basate su SQL. Include le seguenti funzionalità:
- Autenticazione:implementa l'autenticazione personalizzata per le query e le mutazioni della tua app, assicurandoti che solo gli utenti autorizzati possano interagire con i tuoi dati.
- Schema GraphQL:crea e gestisci le strutture di dati utilizzando uno schema GraphQL flessibile personalizzato in base alle esigenze di un'app web di recensioni di film.
- Query e mutazioni SQL:recupera, aggiorna e gestisci i dati in Cloud SQL utilizzando query e mutazioni basate su GraphQL.
- Ricerca avanzata con corrispondenza parziale delle stringhe:utilizza i filtri e le opzioni di ricerca per trovare film in base a campi come titolo, descrizione o tag.
- (Facoltativo) Integrazione della ricerca di vettori: aggiungi la funzionalità di ricerca dei contenuti utilizzando la ricerca di vettori di Firebase Data Connect per offrire un'esperienza utente completa in base agli input e alle preferenze.
Prerequisiti
È necessaria una conoscenza di base di JavaScript.
Cosa imparerai a fare
- Configura Firebase Data Connect con gli emulatori locali.
- Progetta uno schema di dati utilizzando Data Connect e GraphQL.
- Scrivi e testa varie query e mutazioni per un'app di recensioni di film.
- Scopri come Firebase Data Connect genera e utilizza l'SDK nell'app.
- Esegui il deployment dello schema e gestisci il database in modo efficiente.
Che cosa ti serve
- Git
- Visual Studio Code
- Installa Node.js utilizzando nvm-windows (Windows) o nvm (macOS/Linux)
- Se non l'hai ancora fatto, crea un progetto Firebase nella Console Firebase
- (Facoltativo) Per la ricerca di vettori, esegui l'upgrade del progetto al piano tariffario Blaze con pagamento a consumo
2. Configurazione dell'ambiente di sviluppo
In questa fase del codelab ti guideremo nella configurazione dell'ambiente per iniziare a creare la tua app di recensioni di film utilizzando Firebase Data Connect.
- Clona il repository del progetto e installa le dipendenze richieste:
git clone https://github.com/firebaseextended/codelab-dataconnect-web cd codelab-dataconnect-web cd ./app && npm i npm run dev
- Dopo aver eseguito questi comandi, apri http://localhost:5173 nel browser per visualizzare l'app web in esecuzione localmente. Questo è il front-end per creare l'app di recensione dei film e interagire con le sue funzionalità.
- Apri la cartella
codelab-dataconnect-web
clonata utilizzando Visual Studio Code. Qui puoi definire lo schema, scrivere query e testare la funzionalità dell'app. - Per utilizzare le funzionalità di Data Connect, installa l'estensione Visual Studio per Firebase Data Connect.
In alternativa, puoi installare l'estensione dal marketplace di Visual Studio Code o cercarla all'interno di VS Code. - Apri o crea un nuovo progetto Firebase nella Console Firebase.
- Collega il tuo progetto Firebase all'estensione VSCode di Firebase Data Connect. Nell'estensione:
- Fai clic sul pulsante Accedi.
- Fai clic su Collega un progetto Firebase e seleziona il progetto Firebase.
- Avvia gli emulatori Firebase utilizzando l'estensione VS Code di Firebase Data Connect:
fai clic su Avvia emulatori e verifica che gli emulatori siano in esecuzione nel terminale.
3. Esamina il codice di base di avvio
In questa sezione esplorerai le aree chiave del codice di base dell'app. Sebbene nell'app manchino alcune funzionalità, è utile comprendere la struttura complessiva.
Struttura di cartelle e file
Le sottosezioni seguenti forniscono una panoramica della struttura di file e cartelle dell'app.
La directory dataconnect/
Contiene configurazioni di Firebase Data Connect, connettori (che definiscono query e mutazioni) e file di schema.
schema/schema.gql
: definisce lo schema GraphQLconnector/queries.gql
: query necessarie nella tua appconnector/mutations.gql
: Mutazioni necessarie nell'appconnector/connector.yaml
: file di configurazione per la generazione dell'SDK
La directory app/src/
Contiene la logica dell'applicazione e l'interazione con Firebase Data Connect.
firebase.ts
: configurazione per connetterti a un'app Firebase nel tuo progetto Firebase.lib/dataconnect-sdk/
: contiene l'SDK generato. Puoi modificare la posizione di generazione dell'SDK nel fileconnector/connector.yaml
e gli SDK verranno generati automaticamente ogni volta che definisci una query o una mutazione.
4. Definire uno schema per le recensioni di film
In questa sezione, definirai la struttura e le relazioni tra le entità chiave dell'applicazione di film in uno schema. Entità come Movie
, User
, Actor
e Review
vengono mappate alle tabelle di database, con relazioni stabilite utilizzando le direttive dello schema Firebase Data Connect e GraphQL. Una volta implementata, la tua app sarà pronta a gestire tutto, dalla ricerca dei film con il voto più alto e il filtro per genere alla possibilità per gli utenti di lasciare recensioni, contrassegnare i preferiti, esplorare film simili o trovare film consigliati in base all'input di testo tramite la ricerca vettoriale.
Entità e relazioni principali
Il tipo Movie
contiene dettagli chiave come titolo, genere e tag, che l'app utilizza per le ricerche e i profili dei film. Il tipo User
monitora le interazioni degli utenti, come recensioni e preferiti. Reviews
collegano gli utenti ai film, consentendo all'app di mostrare valutazioni e feedback generati dagli utenti.
Le relazioni tra film, attori e utenti rendono l'app più dinamica. La tabella di join MovieActor
consente di visualizzare i dettagli del cast e le filmografie degli attori. Il tipo FavoriteMovie
consente agli utenti di aggiungere film ai preferiti, in modo che l'app possa mostrare un elenco dei preferiti personalizzato ed evidenziare le scelte più popolari.
Configura la tabella Movie
Il tipo Movie
definisce la struttura principale di un'entità film, inclusi campi come title
, genre
, releaseYear
e rating
.
Copia e incolla lo snippet di codice nel file 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]
}
Concetti chiave:
- id: un UUID univoco per ogni film, generato utilizzando
@default(expr: "uuidV4()")
.
Configura la tabella MovieMetadata
Il tipo MovieMetadata
stabilisce una relazione uno a uno con il tipo Movie
. Sono inclusi dati aggiuntivi, come il regista del film.
Copia e incolla lo snippet di codice nel file 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
}
Concetti chiave:
- Film! @ref: fa riferimento al tipo
Movie
, stabilendo una relazione di chiave esterna.
Configura la tabella Actor
Copia e incolla lo snippet di codice nel file dataconnect/schema/schema.gql
:
type Actor @table {
id: UUID!
imageUrl: String!
name: String! @col(name: "name", dataType: "varchar(30)")
}
Il tipo Actor
rappresenta un attore nel database dei film, dove ogni attore può far parte di più film, formando una relazione molti a molti.
Configura la tabella MovieActor
Copia e incolla lo snippet di codice nel file 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"
}
Concetti chiave:
- movie: fa riferimento al tipo Movie, genera implicitamente una chiave esterna movieId: UUID!.
- actor: fa riferimento al tipo di attore, genera implicitamente una chiave esterna actorId: UUID!.
- role: definisce il ruolo dell'attore nel film (ad es. "principale" o "di supporto").
Configura la tabella User
Il tipo User
definisce un'entità utente che interagisce con i film lasciando recensioni o aggiungendoli ai preferiti.
Copia e incolla lo snippet di codice nel file 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
}
Configura la tabella FavoriteMovie
Il tipo FavoriteMovie
è una tabella di join che gestisce le relazioni many-to-many tra gli utenti e i loro film preferiti. Ogni tabella collega un User
a un Movie
.
Copia e incolla lo snippet di codice nel file 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!
}
Concetti chiave:
- movie: fa riferimento al tipo Movie e genera implicitamente una chiave esterna
movieId: UUID!
. - user: fa riferimento al tipo di utente e genera implicitamente una chiave esterna
userId: UUID!
.
Configura la tabella Review
Il tipo Review
rappresenta l'entità recensione e collega i tipi User
e Movie
in una relazione molti-a-molti (un utente può lasciare molte recensioni e ogni film può averne molte).
Copia e incolla lo snippet di codice nel file 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")
}
Concetti chiave:
- user: fa riferimento all'utente che ha lasciato la recensione.
- movie: fa riferimento al film recensito.
- reviewDate: impostato automaticamente sul momento in cui viene creata la recensione utilizzando
@default(expr: "request.time")
.
Campi e valori predefiniti generati automaticamente
Lo schema utilizza espressioni come @default(expr: "uuidV4()")
per generare automaticamente ID e timestamp univoci. Ad esempio, il campo id
nei tipi Movie
e Review
viene compilato automaticamente con un UUID quando viene creato un nuovo record.
Ora che lo schema è definito, la tua app di film ha una base solida per la struttura e le relazioni dei dati.
5. Recuperare i film più popolari e recenti
In questa sezione, inserirai dati simulati dei film negli emulatori locali, quindi implementerai i connettori (query) e il codice TypeScript per chiamare questi connettori nell'applicazione web. Al termine, la tua app potrà recuperare e visualizzare dinamicamente i film più apprezzati e più recenti direttamente dal database.
Inserire dati simulati di film, attori e recensioni
- In VSCode, apri
dataconnect/moviedata_insert.gql
. Assicurati che gli emulatori nell'estensione Firebase Data Connect siano in esecuzione. - Nella parte superiore del file dovresti vedere il pulsante Esegui (locale). Fai clic qui per inserire i dati simulati dei film nel database.
- Controlla il terminale Data Connect Execution (Esecuzione di Data Connect) per verificare che i dati siano stati aggiunti correttamente.
Implementare il connettore
- Apri
dataconnect/movie-connector/queries.gql
. Nei commenti troverai una queryListMovies
di base: Questa query recupera tutti i film e i relativi dettagli (ad esempioquery ListMovies @auth(level: PUBLIC) { movies { id title imageUrl releaseYear genre rating tags description } }
id
,title
,releaseYear
). Tuttavia, non li ordina. - Sostituisci la query
ListMovies
esistente con la seguente query per aggiungere opzioni di ordinamento e limitazioni:# 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 } }
- Fai clic sul pulsante Esegui (locale) per eseguire la query sul database locale. Puoi anche inserire le variabili di query nel riquadro di configurazione prima dell'esecuzione.
Concetti chiave:
movies()
: campo della query GraphQL per recuperare i dati dei film dal database.orderByRating
: parametro per ordinare i film in base alla classificazione (crescente/decrescente).orderByReleaseYear
: parametro per ordinare i film in base all'anno di uscita (in ordine crescente/decrescente).limit
: limita il numero di film restituiti.
Integrare le query nell'app web
In questa parte del codelab, utilizzerai le query definite nella sezione precedente nella tua app web. Gli emulatori Firebase Data Connect generano SDK in base alle informazioni contenute nei file .gql
(in particolare schema.gql
, queries.gql
, mutations.gql
) e nel file connector.yaml
. Questi SDK possono essere chiamati direttamente nella tua applicazione.
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dell'istruzione di importazione in alto: La funzioneimport { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";
listMovies
, il tipo di rispostaListMoviesData
e l'enumOrderDirection
sono tutti SDK generati dagli emulatori Firebase Data Connect in base allo schema e alle query che hai definito in precedenza . - Sostituisci le funzioni
handleGetTopMovies
ehandleGetLatestMovies
con il seguente codice:// 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; } };
Concetti chiave:
listMovies
: una funzione generata automaticamente che chiama la querylistMovies
per recuperare un elenco di film. Sono incluse le opzioni per l'ordinamento in base alla classificazione o all'anno di uscita e per limitare il numero di risultati.ListMoviesData
: il tipo di risultato utilizzato per visualizzare i 10 film più recenti e più popolari nella home page dell'app.
Guarda come funziona
Ricarica l'app web per vedere la query in azione. La home page ora mostra in modo dinamico l'elenco dei film, recuperando i dati direttamente dal database locale. Vedrai i film più apprezzati e più recenti, in base ai dati che hai appena impostato.
6. Mostrare i dettagli di film e attori
In questa sezione, implementerai la funzionalità per recuperare informazioni dettagliate su un film o un attore utilizzando i relativi ID univoci. Ciò comporta non solo il recupero dei dati dalle rispettive tabelle, ma anche l'unione di tabelle correlate per visualizzare dettagli completi, come recensioni di film e filmografie degli attori.
Implementare i connettori
- Apri
dataconnect/movie-connector/queries.gql
nel tuo progetto. - Aggiungi le seguenti query per recuperare i dettagli di film e attori:
# 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 } } }
- Salva le modifiche e rivedi le query.
Concetti chiave:
movie()
/actor()
: campi di query GraphQL per recuperare un singolo film o attore dalla tabellaMovies
oActors
._on_
: consente l'accesso diretto ai campi di un tipo associato che ha una relazione di chiave esterna. Ad esempio,reviews_on_movie
recupera tutte le recensioni relative a un film specifico._via_
: utilizzato per gestire le relazioni many-to-many tramite una tabella di join. Ad esempio,actors_via_MovieActor
accede al tipoActor
tramite la tabella di joinMovieActor
e la condizionewhere
filtra gli attori in base al loro ruolo (ad esempio, "principale" o "di supporto").
Testa la query inserendo dati simulati
- Nel riquadro di esecuzione di Data Connect, puoi testare la query inserendo ID simulati, ad esempio:
{"id": "550e8400-e29b-41d4-a716-446655440000"}
- Fai clic su Esegui (locale) per
GetMovieById
per recuperare i dettagli di "Quantum Paradox" (il film simulato a cui si riferisce l'ID riportato sopra).
Integrare le query nell'app web
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dalle seguenti importazioni:import { getMovieById, GetMovieByIdData } from "@movie/dataconnect"; import { GetActorByIdData, getActorById } from "@movie/dataconnect";
- Sostituisci le funzioni
handleGetMovieById
ehandleGetActorById
con il seguente codice:// 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; } };
Concetti chiave:
getMovieById
/getActorById
: si tratta di funzioni generate automaticamente che richiamano le query che hai definito, recuperando informazioni dettagliate su un film o un attore specifico.GetMovieByIdData
/GetActorByIdData
: si tratta dei tipi di risultati, utilizzati per visualizzare i dettagli di film e attori nell'app.
Guarda come funziona
Ora vai alla home page della tua app web. Fai clic su un film per visualizzarne tutti i dettagli, inclusi attori e recensioni, ovvero informazioni tratte da tabelle correlate. Allo stesso modo, facendo clic su un attore vengono visualizzati i film in cui ha recitato.
7. Gestire l'autenticazione utente
In questa sezione, implementerai le funzionalità di accesso e di uscita degli utenti utilizzando Firebase Authentication. Utilizzerai inoltre i dati di Firebase Authentication per recuperare o eseguire l'upsert dei dati utente direttamente in Firebase DataConnect, garantendo una gestione sicura degli utenti all'interno della tua app.
Implementare i connettori
- Apri
mutations.gql
indataconnect/movie-connector/
. - Aggiungi la seguente mutazione per creare o aggiornare l'utente attualmente autenticato:
# Create or update the current authenticated user mutation UpsertUser($username: String!) @auth(level: USER) { user_upsert( data: { id_expr: "auth.uid" username: $username } ) }
Concetti chiave:
id_expr: "auth.uid"
: viene utilizzatoauth.uid
, fornito direttamente da Firebase Authentication, non dall'utente o dall'app, aggiungendo un ulteriore livello di sicurezza garantendo che l'ID utente venga gestito in modo sicuro e automatico.
Recupero dell'utente corrente
- Apri
queries.gql
indataconnect/movie-connector/
. - Aggiungi la seguente query per recuperare l'utente corrente:
# 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 } } } } }
Concetti chiave:
auth.uid
: viene recuperato direttamente da Firebase Authentication, garantendo l'accesso sicuro ai dati specifici dell'utente.- Campi
_on_
: questi campi rappresentano le tabelle unite:reviews_on_user
: recupera tutte le recensioni relative all'utente, inclusiid
etitle
del film.favorite_movies_on_user
: recupera tutti i film contrassegnati come preferiti dall'utente, incluse informazioni dettagliate comegenre
,releaseYear
,rating
emetadata
.
Integrare le query nell'app web
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dalle seguenti importazioni:import { upsertUser } from "@movie/dataconnect"; import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
- Sostituisci le funzioni
handleAuthStateChange
ehandleGetCurrentUser
con il seguente codice:// 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; } };
Concetti chiave:
handleAuthStateChange
: questa funzione ascolta le modifiche dello stato di autenticazione. Quando un utente accede, vengono impostati i suoi dati e viene chiamata la mutazioneupsertUser
per creare o aggiornare le sue informazioni nel database.handleGetCurrentUser
: recupera il profilo dell'utente corrente utilizzando la querygetCurrentUser
, che recupera le recensioni e i film preferiti dell'utente.
Guarda come funziona
Ora fai clic sul pulsante "Accedi con Google" nella barra di navigazione. Puoi accedere utilizzando l'emulatore di Firebase Authentication. Dopo aver eseguito l'accesso, fai clic su "Il mio profilo". Per il momento sarà vuoto, ma hai impostato le basi per la gestione dei dati specifici dell'utente nella tua app.
8. Implementare le interazioni utente
In questa sezione del codelab, implementerai le interazioni degli utenti nell'app di recensione dei film, in particolare consentendo agli utenti di gestire i loro film preferiti e di lasciare o eliminare recensioni.
Consentire a un utente di aggiungere un film ai preferiti
In questa sezione, configurerai il database in modo che gli utenti possano aggiungere un film ai preferiti.
Implementare i connettori
- Apri
mutations.gql
indataconnect/movie-connector/
. - Aggiungi le seguenti mutazioni per gestire l'aggiunta di film ai preferiti:
# 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 }) }
Concetti chiave:
userId_expr: "auth.uid"
: utilizzaauth.uid
, fornito direttamente da Firebase Authentication, per garantire che vengano visualizzati o modificati solo i dati dell'utente autenticato.
Verificare se un film è tra i preferiti
- Apri
queries.gql
indataconnect/movie-connector/
. - Aggiungi la seguente query per verificare se un film è tra i preferiti:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) { favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) { movieId } }
Concetti chiave:
auth.uid
: garantisce l'accesso sicuro ai dati specifici dell'utente utilizzando Firebase Authentication.favorite_movie
: controlla la tabella di joinfavorite_movies
per verificare se un film specifico è contrassegnato come preferito dall'utente corrente.
Integrare le query nell'app web
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dalle seguenti importazioni:import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
- Sostituisci le funzioni
handleAddFavoritedMovie
,handleDeleteFavoritedMovie
ehandleGetIfFavoritedMovie
con il seguente codice:// 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; } };
Concetti chiave:
handleAddFavoritedMovie
ehandleDeleteFavoritedMovie
: utilizza le mutazioni per aggiungere o rimuovere in modo sicuro un film dai preferiti dell'utente.handleGetIfFavoritedMovie
: utilizza la querygetIfFavoritedMovie
per verificare se un film è contrassegnato come preferito dall'utente.
Guarda come funziona
Ora puoi aggiungere o rimuovere film dai preferiti facendo clic sull'icona a forma di cuore nelle schede dei film e nella pagina dei dettagli del film. Inoltre, puoi visualizzare i tuoi film preferiti nella pagina del tuo profilo.
Consentire agli utenti di lasciare o eliminare recensioni
Successivamente, implementerai la sezione per la gestione delle recensioni degli utenti nell'app.
Implementare i connettori
In mutations.gql
(dataconnect/movie-connector/mutations.gql
): aggiungi le seguenti mutazioni:
# 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 })
}
Concetti chiave:
userId_expr: "auth.uid"
: garantisce che le recensioni siano associate all'utente autenticato.reviewDate_date: { today: true }
: genera automaticamente la data corrente della revisione utilizzando DataConnect, eliminando la necessità di inserire manualmente i dati.
Integrare le query nell'app web
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dalle seguenti importazioni:import { addReview, deleteReview } from "@movie/dataconnect";
- Sostituisci le funzioni
handleAddReview
ehandleDeleteReview
con il seguente codice:// 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; } };
Concetti chiave:
handleAddReview
: chiama la mutazioneaddReview
per aggiungere una recensione al film specificato, collegandola in modo sicuro all'utente autenticato.handleDeleteReview
: utilizza la mutazionedeleteReview
per rimuovere una recensione di un film da parte dell'utente autenticato.
Guarda come funziona
Ora gli utenti possono lasciare recensioni dei film nella pagina dei dettagli del film. Possono anche visualizzare ed eliminare le loro recensioni nella pagina del profilo, avendo così il pieno controllo sulle loro interazioni con l'app.
9. Filtri avanzati e corrispondenza parziale del testo
In questa sezione, implementerai funzionalità di ricerca avanzata, consentendo agli utenti di cercare film in base a una serie di valutazioni e anni di uscita, filtrare per generi e tag, eseguire la corrispondenza parziale del testo nei titoli o nelle descrizioni e persino combinare più filtri per risultati più precisi.
Implementare i connettori
- Apri
queries.gql
indataconnect/movie-connector/
. - Aggiungi la seguente query per supportare varie funzionalità di ricerca:
# 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 } } }
Concetti chiave:
- Operatore
_and
: combina più condizioni in un'unica query, consentendo di filtrare la ricerca in base a diversi campi comereleaseYear
,rating
egenre
. - Operatore
contains
: cerca corrispondenze di testo parziali all'interno dei campi. In questa query vengono cercate corrispondenze intitle
,description
,name
oreviewText
. - Clausola
where
: specifica le condizioni per filtrare i dati. Ogni sezione (film, attori, recensioni) utilizza una clausolawhere
per definire i criteri specifici per la ricerca.
Integrare le query nell'app web
- In
MovieService
(app/src/lib/MovieService.tsx
), rimuovi il commento dalle seguenti importazioni:import { searchAll, SearchAllData } from "@movie/dataconnect";
- Sostituisci la funzione
handleSearchAll
con il seguente codice:// 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; } };
Concetti chiave:
handleSearchAll
: questa funzione utilizza la querysearchAll
per eseguire una ricerca in base all'input dell'utente, filtrando i risultati in base a parametri quali anno, valutazione, genere e corrispondenze parziali del testo.
Guarda come funziona
Vai alla pagina "Ricerca avanzata" dalla barra di navigazione nell'app web. Ora puoi cercare film, attori e recensioni utilizzando vari filtri e input, ottenendo risultati di ricerca dettagliati e personalizzati.
10. (Facoltativo) Esegui il deployment su Cloud (è necessaria la fatturazione)
Ora che hai completato l'iterazione di sviluppo locale, è il momento di eseguire il deployment dello schema, dei dati e delle query sul server. Puoi farlo utilizzando l'estensione VS Code di Firebase Data Connect o l'interfaccia a riga di comando di Firebase.
Eseguire l'upgrade del piano tariffario di Firebase
Per integrare Firebase Data Connect con Cloud SQL per PostgreSQL, il progetto Firebase deve utilizzare il piano tariffario Blaze con pagamento a consumo, il che significa che deve essere collegato a un account di fatturazione Cloud.
- Un account di fatturazione Cloud richiede un metodo di pagamento, ad esempio una carta di credito.
- Se non hai mai utilizzato Firebase e Google Cloud, controlla se hai l'idoneità a ricevere un credito di 300$e un account di fatturazione Cloud per la prova senza costi.
- Se stai svolgendo questo codelab nell'ambito di un evento, chiedi all'organizzatore se sono disponibili crediti Cloud.
Per eseguire l'upgrade del progetto al piano Blaze:
- Nella console Firebase, seleziona l'upgrade del piano.
- Seleziona il piano Blaze. Segui le istruzioni sullo schermo per collegare un account di fatturazione Cloud al tuo progetto.
Se hai dovuto creare un account di fatturazione Cloud nell'ambito di questo upgrade, potresti dover tornare al flusso di upgrade nella console Firebase per completarlo.
Collegare l'app web al progetto Firebase
- Registra la tua app web nel tuo progetto Firebase utilizzando la Console Firebase:
- Apri il progetto e fai clic su Aggiungi app.
- Per il momento, ignora la configurazione e l'installazione dell'SDK, ma assicurati di copiare l'oggetto
firebaseConfig
generato.
- Sostituisci il
firebaseConfig
esistente inapp/src/lib/firebase.tsx
con la configurazione che hai appena copiato dalla console 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" };
- Crea l'app web:torna in VS Code, nella cartella
app
, utilizza Vite per compilare l'app web per il deployment in hosting:cd app npm run build
Configurare l'autenticazione Firebase nel progetto Firebase
- Configura Firebase Authentication con Accedi con Google.
- (Facoltativo) Consenti i domini per Firebase Authentication utilizzando la Console Firebase (ad esempio
http://127.0.0.1
).- Nelle impostazioni Autenticazione, vai a Domini autorizzati.
- Fai clic su "Aggiungi dominio" e includi il tuo dominio locale nell'elenco.
Esegui il deployment con l'interfaccia a riga di comando di Firebase
- In
dataconnect/dataconnect.yaml
, assicurati che l'ID istanza, il database e l'ID servizio corrispondano al tuo progetto: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"]
- Assicurati di aver configurato l'interfaccia a riga di comando di Firebase con il tuo progetto:
npm i -g firebase-tools firebase login --reauth firebase use --add
- Nel terminale, esegui il seguente comando per eseguire il deployment:
firebase deploy --only dataconnect,hosting
- Esegui questo comando per confrontare le modifiche allo schema:
firebase dataconnect:sql:diff
- Se le modifiche sono accettabili, applicale con:
firebase dataconnect:sql:migrate
L'istanza Cloud SQL per PostgreSQL verrà aggiornata con lo schema e i dati di cui è stato eseguito il deployment finale. Puoi monitorare lo stato nella Console Firebase.
Ora dovresti essere in grado di vedere la tua app in azione all'indirizzo your-project.web.app/
. Inoltre, puoi fare clic su Esegui (produzione) nel riquadro Firebase Data Connect, proprio come hai fatto con gli emulatori locali, per aggiungere dati all'ambiente di produzione.
11. (Facoltativo) Ricerca di vettori con Firebase Data Connect (fatturazione obbligatoria)
In questa sezione, attiverai la ricerca di vettori nella tua app di recensioni di film utilizzando Firebase Data Connect. Questa funzionalità consente ricerche basate sui contenuti, ad esempio trovare film con descrizioni simili utilizzando gli embedding vettoriali.
Questo passaggio richiede che tu abbia completato l'ultimo passaggio di questo codelab per il deployment su Google Cloud.
Aggiornare lo schema per includere gli embedding per un campo
In dataconnect/schema/schema.gql
, aggiungi il campo descriptionEmbedding
alla tabella 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
}
Concetti chiave:
descriptionEmbedding: Vector @col(size:768)
: questo campo memorizza gli embedding semantici delle descrizioni dei film, consentendo la ricerca di contenuti basata su vettori nella tua app.
Attivare Vertex AI
- Segui la guida ai prerequisiti per configurare le API Vertex AI da Google Cloud. Questo passaggio è essenziale per supportare la funzionalità di ricerca di vettori e la generazione di embedding.
- Esegui nuovamente il deployment dello schema per attivare la ricerca di
pgvector
e di vettori facendo clic su "Esegui il deployment in produzione" utilizzando l'estensione VS Code di Firebase Data Connect.
Compilare il database con gli embedding
- Apri la cartella
dataconnect
in VS Code. - Fai clic su Esegui(locale) in
optional_vector_embed.gql
per compilare il database con gli embedding dei film.
Aggiungere una query di ricerca di vettori
In dataconnect/movie-connector/queries.gql
, aggiungi la seguente query per eseguire ricerche vettoriali:
# 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
}
}
Concetti chiave:
compare_embed
: specifica il modello di embedding (textembedding-gecko@003
) e il testo di input ($query
) per il confronto.method
: specifica il metodo di somiglianza (L2
), che rappresenta la distanza euclidea.within
: limita la ricerca ai film con una distanza L2 pari o inferiore a 2, concentrandosi sulle corrispondenze dei contenuti più strette.limit
: limita il numero di risultati restituiti a 5.
Implementare la funzione di ricerca di vettori nella tua app
Ora che lo schema e la query sono configurati, integra la ricerca di vettori nel livello di servizio della tua app. Questo passaggio ti consente di chiamare la query di ricerca dalla tua app web.
- In
app/src/lib/
MovieService.ts
, rimuovi il commento dalle seguenti importazioni dagli SDK. Funzionerà come qualsiasi altra query.import { searchMovieDescriptionUsingL2similarity, SearchMovieDescriptionUsingL2similarityData, } from "@movie/dataconnect";
- Aggiungi la seguente funzione per integrare la ricerca basata su vettori nell'app:
// 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; } };
Concetti chiave:
searchMoviesByDescription
: questa funzione chiama la querysearchMovieDescriptionUsingL2similarity
, passando il testo inserito per eseguire una ricerca di contenuti basata su vettori.
Guarda come funziona
Vai alla sezione "Ricerca di vettori" nella barra di navigazione e digita frasi come "romantico e moderno". Vedrai un elenco di film corrispondenti ai contenuti che stai cercando oppure puoi andare alla pagina dei dettagli di qualsiasi film e controllare la sezione dei film simili in fondo alla pagina.
12. Conclusione
Congratulazioni, dovresti riuscire a utilizzare l'app web. Se vuoi utilizzare i tuoi dati sui film, non preoccuparti: inserisci i tuoi dati utilizzando l'estensione Firebase Data Connect imitando i file _insert.gql
o aggiungili tramite il riquadro di esecuzione di Data Connect in VS Code.