1. Zanim zaczniesz
W tym laboratorium programistycznym zintegrujesz Firebase Data Connect z bazą danych Cloud SQL, aby utworzyć aplikację internetową do przeglądania filmów. Ukończona aplikacja pokazuje, jak Firebase Data Connect upraszcza proces tworzenia aplikacji opartych na SQL. Obejmuje ona te funkcje:
- Uwierzytelnianie: zaimplementuj niestandardowe uwierzytelnianie w przypadku zapytań i mutacji w aplikacji, aby mieć pewność, że tylko upoważnione osoby będą mieć dostęp do Twoich danych.
- Schemat GraphQL: twórz struktury danych i zarządzaj nimi za pomocą elastycznego schematu GraphQL dostosowywanego do potrzeb aplikacji internetowej z recenzjami filmów.
- Zapytania i zmiany w formie SQL: pobieraj, aktualizuj i zarządzaj danymi w Cloud SQL za pomocą zapytań i zmian w formie GraphQL.
- Wyszukiwanie zaawansowane z dopasowaniem częściowym: korzystaj z filtrów i opcji wyszukiwania, aby znajdować filmy na podstawie pól takich jak tytuł, opis czy tagi.
- Opcjonalnie: integracja z wyszukiwaniem wektorów: dodaj funkcję wyszukiwania treści za pomocą wyszukiwania wektorów w Firebase Data Connect, aby zapewnić użytkownikom bogate wrażenia na podstawie ich preferencji i danych wejściowych.
Wymagania wstępne
Musisz mieć podstawową znajomość języka JavaScript.
Czego się nauczysz
- Skonfiguruj Firebase Data Connect za pomocą emulatorów lokalnych.
- Zaprojektuj schemat danych za pomocą Data Connect i GraphQL.
- Napisz i przetestuj różne zapytania i mutacje dla aplikacji z recenzjami filmów.
- Dowiedz się, jak Firebase Data Connect generuje pakiet SDK i z niego korzysta w aplikacji.
- Wdróż schemat i skutecznie zarządzaj bazą danych.
Co będzie Ci potrzebne
- Git
- Visual Studio Code
- Zainstaluj Node.js za pomocą nvm-windows (Windows) lub nvm (macOS/Linux).
- Jeśli nie masz jeszcze projektu Firebase, utwórz go w konsoli Firebase.
- (Opcjonalnie) Aby korzystać z wyszukiwania wektorów, przenieś projekt na abonament Blaze
Konfigurowanie środowiska programistycznego
W tej sekcji znajdziesz instrukcje konfigurowania środowiska, aby rozpocząć tworzenie aplikacji do recenzowania filmów za pomocą Firebase Data Connect.
Krok 1. Sklonuj repozytorium projektu
Zacznij od sklonowania repozytorium projektu i zainstalowania wymaganych zależności:
git clone https://github.com/firebaseextended/codelab-dataconnect-web cd codelab-dataconnect-web cd ./app && npm i npm run dev
- Po wykonaniu tych poleceń otwórz w przeglądarce adres http://localhost:5173, aby wyświetlić aplikację internetową uruchomioną lokalnie. Jest to interfejs do tworzenia aplikacji do recenzowania filmów i interakcji z jej funkcjami.
Krok 2. Otwórz projekt w Visual Studio Code
Otwórz sklonowany folder codelab-dataconnect-web
za pomocą Visual Studio Code. Tutaj zdefiniujesz schemat, napiszesz zapytania i przetestujesz funkcje aplikacji.
Krok 3. Zainstaluj rozszerzenie Firebase Data Connect do Visual Studio
Aby korzystać z funkcji Data Connect, zainstaluj rozszerzenie Firebase Data Connect do Visual Studio.Możesz je zainstalować z Visual Studio Code Marketplace lub wyszukać w VS Code.
- Możesz też zainstalować je z platformy Marketplace Visual Studio Code lub wyszukać w VS Code.
Krok 4. Utwórz projekt Firebase
Jeśli nie masz jeszcze projektu Firebase, otwórz konsolę Firebase i utwórz nowy projekt Firebase. Następnie w rozszerzeniu Firebase Data Connect w VSCode:
- Kliknij przycisk Zaloguj się.
- Kliknij Połącz z projektem Firebase i wybierz projekt utworzony w konsoli Firebase.
Krok 5. Uruchom emulatory Firebase
W rozszerzeniu Firebase Data Connect w VSCode kliknij Uruchom emulatory i sprawdź, czy emulatory działają w terminalu.
2. Sprawdzanie kodu źródłowego bazy danych
W tej sekcji poznasz kluczowe obszary kodu źródłowego aplikacji startowej. Aplikacja nie zawiera niektórych funkcji, ale warto zapoznać się z jej ogólną strukturą.
Struktura folderów i plików
Oto krótkie omówienie struktury folderów i plików aplikacji:
dataconnect/
Zawiera konfiguracje Firebase Data Connect, łączniki (określające zapytania i mutacje) oraz pliki schematu.
schema/schema.gql
: definiuje schemat GraphQLconnector/queries.gql
: zapytania potrzebne w aplikacji.connector/mutations.gql
: w aplikacji są potrzebne mutacje.connector/connector.yaml:
Plik konfiguracji do generowania pakietu SDK
app/src/
Zawiera logikę aplikacji i interakcje z Firebase Data Connect.
firebase.ts
: konfiguracja połączenia z aplikacją Firebase w konsoli.lib/dataconnect-sdk/
: ten folder zawiera wygenerowany pakiet SDK. Lokalizację generowania pakietu SDK możesz edytować w pliku connector/connector.yaml. Pakiety SDK będą generowane automatycznie za każdym razem, gdy zdefiniujesz zapytanie lub mutację.
3. Definiowanie schematu dla recenzji filmów
W tej sekcji określisz strukturę i relacje między kluczowymi elementami w aplikacji dotyczącej filmów w schemacie. Elementy takie jak Movie
, User
, Actor
i Review
są mapowane na tabele baz danych, a relacje są ustanawiane za pomocą dyrektyw schematu Firebase Data Connect i GraphQL. Gdy to zrobisz, aplikacja będzie mogła obsługiwać wszystkie funkcje, od wyszukiwania filmów z najlepszymi ocenami i filtrowania według gatunku po umożliwianie użytkownikom dodawania recenzji, oznaczania ulubionych, przeglądania podobnych filmów oraz znajdowania filmów polecanych na podstawie tekstu wpisanego w wyszukiwarce wektorowej.
Podstawowe typy jednostek i relacji
Typ Movie
zawiera kluczowe informacje, takie jak tytuł, gatunek i tagi, których aplikacja używa do wyszukiwania i profili filmów. Typ User
śledzi interakcje użytkowników, takie jak opinie i ulubione. Reviews
łączyć użytkowników z filmami, umożliwiając aplikacji wyświetlanie ocen i opinii użytkowników;
Relacje między filmami, aktorami i użytkownikami sprawiają, że aplikacja jest bardziej dynamiczna. Tabela złączenia MovieActor
ułatwia wyświetlanie szczegółów obsady i filmografii aktorów. Typ FavoriteMovie
pozwala użytkownikom dodawać filmy do ulubionych, dzięki czemu aplikacja może wyświetlać spersonalizowaną listę ulubionych i wyróżniać popularne pozycje.
Tabela Film
Typ Movie definiuje główną strukturę encji filmu, w tym pola takie jak tytuł, gatunek, rok wydania i ocena.
Skopiuj i wklej fragment kodu do pliku 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]
}
Podsumowanie:
- id: unikalny identyfikator UUID dla każdego filmu wygenerowany za pomocą funkcji
@default(expr: "uuidV4()")
.
Tabela MovieMetadata
Typ MovieMetadata ustanawia relację jeden do jednego z typem Movie. Zawiera ono dodatkowe dane, takie jak reżyser filmu.
Skopiuj i wklej fragment kodu do pliku 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
}
Podsumowanie:
- Film! @ref: odwołuje się do typu
Movie
, ustanawiając relację klucza obcego.
Tabela aktorów
Skopiuj i wklej fragment kodu do pliku dataconnect/schema/schema.gql
:
type Actor @table {
id: UUID!
imageUrl: String!
name: String! @col(name: "name", dataType: "varchar(30)")
}
Typ Actor
reprezentuje aktora w bazie danych o filmach, gdzie każdy aktor może występować w kilku filmach, tworząc relację „wiele do wielu”.
Tabela MovieActor
Skopiuj i wklej fragment kodu do pliku 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"
}
Podsumowanie:
- movie: odwołuje się do typu Movie, domyślnie generuje klucz obcy movieId: UUID!.
- actor: odwołuje się do typu Użytkownik, który wykonał czynność, i po cichu generuje klucz obcy actorId: UUID!.
- role: określa rolę aktora w filmie (np. „główny” lub „dodatkowy”).
Tabela użytkowników
Typ User
definiuje użytkownika, który wchodzi w interakcję z filmami, pozostawiając opinie lub dodając je do ulubionych.
Skopiuj i wklej fragment kodu do pliku 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
}
Tabela UlubioneFilmy
Typ FavoriteMovie
to tabela złączeń, która obsługuje relacje wiele do wielu między użytkownikami a ich ulubionymi filmami lub aktorami. Każda tabela łączy element User
z elementem Movie
.
Skopiuj i wklej fragment kodu do pliku 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!
}
Podsumowanie:
- movie: odwołuje się do typu Movie, domyślnie generuje klucz obcy movieId: UUID!.
- user: odwołuje się do typu użytkownika, domyślnie generuje klucz obcy userId: UUID!.
Tabela opinii
Typ opinii reprezentuje element opinii i łączy typy Użytkownik i Film w relacji wiele do wielu (jeden użytkownik może pozostawić wiele opinii, a każdy film może mieć wiele opinii).
Skopiuj i wklej fragment kodu do pliku 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")
}
Podsumowanie:
- user:odnosi się do użytkownika, który zostawił opinię.
- movie: odnosi się do filmu, który jest sprawdzany.
- reviewDate: wartość ustawiana automatycznie na czas utworzenia opinii za pomocą elementu
@default(expr: "request.time")
.
Pola generowane automatycznie i wartości domyślne
Schemat używa wyrażeń takich jak @default(expr: "uuidV4()")
do automatycznego generowania unikalnych identyfikatorów i sygnatur czasowych. Na przykład pole identyfikatora w typach Film i Recenzja jest automatycznie wypełniane identyfikatorem UUID podczas tworzenia nowego rekordu.
Teraz, gdy schemat jest zdefiniowany, aplikacja filmowa ma solidną podstawę dla struktury danych i ich relacji.
4. Pobieranie najpopularniejszych i najnowszych filmów
W tej sekcji wstawisz do lokalnych emulatorów dane testowe dotyczące filmów, a potem zaimplementujesz łączniki (zapytania) i kod TypeScript, aby wywołać te łączniki w aplikacji internetowej. Ostatecznie Twoja aplikacja będzie mogła dynamicznie pobierać i wyświetlać najnowsze filmy z najlepszymi ocenami bezpośrednio z bazy danych.
Wstawianie danych dotyczących testowego filmu, aktora i recenzji
- W VSCode otwórz
dataconnect/moviedata_insert.gql
. Upewnij się, że emulatory w rozszerzeniu Firebase Data Connect działają. - U góry pliku powinien być widoczny przycisk Uruchom (lokalnie). Kliknij, aby wstawić do bazy danych dane testowe filmu.
- Sprawdź terminal Wykonanie Data Connect, aby potwierdzić, że dane zostały dodane.
Wdrażanie oprogramowania sprzęgającego
- Otwórz pokój
dataconnect/movie-connector/queries.gql
. W komentarzach znajdziesz podstawowe zapytanieListMovies
:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
To zapytanie pobiera wszystkie filmy i ich szczegóły (np. identyfikator, tytuł, rok wydania). Nie powoduje jednak ich sortowania.
- Zastąp zapytanie
ListMovies
tym poniżej, aby dodać opcje sortowania i ograniczenia:
# 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
}
}
Kliknij przycisk Uruchom (lokalnie), aby wykonać zapytanie w bazie danych lokalnej. Zanim uruchomisz zapytanie, możesz też wprowadzić zmienne zapytania w panelu konfiguracji.
Podsumowanie:
- movies(): pole zapytania GraphQL służące do pobierania danych o filmach z bazy danych.
- orderByRating: parametr do sortowania filmów według oceny (rosnąco/malejąco).
- orderByReleaseYear: parametr do sortowania filmów według roku wydania (rosnąco/malejąco).
- limit: ogranicza liczbę zwracanych filmów.
Integracja zapytań w aplikacji internetowej
W tej części użyjesz w aplikacji internetowej zapytań zdefiniowanych w poprzedniej sekcji. Emulatorów Firebase Data Connect generują pakiety SDK na podstawie informacji w plikach .gql (schema.gql, queries.gql, mutations.gql) i connector.yaml. Te zestawy SDK można wywoływać bezpośrednio w aplikacji.
- W pliku
MovieService
(app/src/lib/MovieService.tsx
) odkomentuj instrukcję importu u góry:
import { listMovies, ListMoviesData, OrderDirection } from "@movie/dataconnect";
Funkcja listMovies
, typ odpowiedzi ListMoviesData
i typ zbioru OrderDirection
to pakiety SDK wygenerowane przez emulatory Firebase Data Connect na podstawie wcześniej zdefiniowanego schematu i zapytań .
- Zastąp funkcje
handleGetTopMovies
ihandleGetLatestMovies
tym kodem:
// 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;
}
};
Podsumowanie:
- listMovies: automatycznie wygenerowana funkcja, która wywołuje zapytanie listMovies w celu pobrania listy filmów. Zawiera ona opcje sortowania według oceny lub roku wydania oraz opcję ograniczania liczby wyników.
- ListMoviesData: typ wyników używany do wyświetlania 10 najpopularniejszych i najnowszych filmów na stronie głównej.
Jak to działa
Załaduj ponownie aplikację internetową, aby zobaczyć zapytanie w działaniu. Strona główna wyświetla teraz dynamicznie listę filmów, pobierając dane bezpośrednio z bazy danych lokalnej. Najwyżej oceniane i najnowsze filmy będą się wyświetlać automatycznie, zgodnie z niedawno ustawionymi przez Ciebie danymi.
5. Wyświetlanie szczegółów filmu i aktora
W tej sekcji zaimplementujesz funkcję umożliwiającą pobieranie szczegółowych informacji o filmie lub aktorze na podstawie ich unikalnych identyfikatorów. Polega to nie tylko na pobieraniu danych z odpowiednich tabel, ale też na złączaniu powiązanych tabel w celu wyświetlania szczegółowych informacji, takich jak recenzje filmów czy filmografia aktora.
Implementacja łączy
- Otwórz
dataconnect/movie-connector/queries.gql
w projekcie. - Dodaj te zapytania, aby pobrać szczegóły filmu i aktora:
# 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
}
}
}
- Zapisz zmiany i sprawdź zapytania.
Podsumowanie:
movie()
/actor()
: pola zapytania GraphQL do pobierania pojedynczego filmu lub aktora z tabeli Filmy lub Aktorzy._on_
: umożliwia bezpośredni dostęp do pól powiązanego typu, który ma relację obcego klucza. Na przykładreviews_on_movie
pobiera wszystkie recenzje powiązane z danym filmem._via_
: służy do przechodzenia między relacjami „wiele do wielu” za pomocą tabeli złączeń. Na przykładactors_via_MovieActor
uzyskuje dostęp do typu „Aktor” za pomocą tabeli złączenia „MovieActor”, a warunekwhere
filtruje aktorów na podstawie ich roli (np. „główny” lub „dodatkowy”).
W panelu wykonania usługi Data Connectors możesz przetestować zapytanie, podając fikcyjne identyfikatory, takie jak:
{"id": "550e8400-e29b-41d4-a716-446655440000"}
Kliknij Uruchom (lokalnie) obok GetMovieById
, aby pobrać szczegóły dotyczące „Quantum Paradox” (filmu symulacyjnego, do którego odnosi się powyższy identyfikator).
Integracja zapytań w aplikacji internetowej
- W pliku
MovieService
(app/src/lib/MovieService.tsx
) odkomentuj te importy:
import { getMovieById, GetMovieByIdData } from "@movie/dataconnect";
import { GetActorByIdData, getActorById } from "@movie/dataconnect";
- Zastąp funkcje
handleGetMovieById
ihandleGetActorById
tym kodem:
// 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;
}
};
Podsumowanie:
getMovieById
/getActorById
: to automatycznie generowane funkcje, które wywołują zdefiniowane przez Ciebie zapytania, aby pobrać szczegółowe informacje o konkretnym filmie lub aktorze.GetMovieByIdData
/GetActorByIdData
: to typy wyników, które służą do wyświetlania w aplikacji szczegółów filmów i aktorów.
Jak to działa
Otwórz stronę główną swojej aplikacji internetowej. Kliknij film, aby wyświetlić wszystkie jego szczegóły, w tym informacje o aktorach i recenzjach, które zostały pobrane z powiązanych tabel. Podobnie, kliknięcie aktora spowoduje wyświetlenie filmów, w których zagrał.
6. Obsługa uwierzytelniania użytkowników
W tej sekcji zaimplementujesz funkcje logowania i wylogowywania użytkowników za pomocą uwierzytelniania Firebase. Dane Uwierzytelniania Firebase możesz też używać do bezpośredniego pobierania lub aktualizowania danych użytkowników w Firebase DataConnect, co zapewni bezpieczne zarządzanie użytkownikami w aplikacji.
Implementacja łączy
- Otwórz
mutations.gql
wdataconnect/movie-connector/
. - Aby utworzyć lub zaktualizować bieżącego uwierzytelnionego użytkownika, dodaj tę mutację:
# Create or update the current authenticated user
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Podsumowanie:
id_expr: "auth.uid"
: ta opcja używaauth.uid
, który jest dostarczany bezpośrednio przez Uwierzytelnianie Firebase, a nie przez użytkownika ani aplikację. Zapewnia to dodatkowy poziom zabezpieczeń, ponieważ identyfikator użytkownika jest przetwarzany w sposób bezpieczny i automatyczny.
Następnie otwórz queries.gql
w dataconnect/movie-connector/
.
Dodaj to zapytanie, aby pobrać bieżącego użytkownika:
# 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
}
}
}
}
}
Najważniejsze wnioski:
auth.uid
: ten identyfikator jest pobierany bezpośrednio z Uwierzytelniania Firebase, co zapewnia bezpieczny dostęp do danych dotyczących użytkownika._on_
Pola: te pola reprezentują tabele złączenia:reviews_on_user
: pobiera wszystkie opinie powiązane z użytkownikiem, w tym identyfikator i tytuł filmu.favorite_movies_on_user
: pobiera wszystkie filmy oznaczone przez użytkownika jako ulubione, w tym szczegółowe informacje, takie jak gatunek, rok wydania, ocena i metadane.
Integracja zapytań w aplikacji internetowej
- W MovieService (
app/src/lib/MovieService.tsx
) odkomentuj te importy:
import { upsertUser } from "@movie/dataconnect";
import { getCurrentUser, GetCurrentUserData } from "@movie/dataconnect";
- Zastąp funkcje
handleAuthStateChange
ihandleGetCurrentUser
tym kodem:
// 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;
}
};
Podsumowanie:
handleAuthStateChange
: ta funkcja sprawdza zmiany stanu uwierzytelniania. Gdy użytkownik się zaloguje, usługa ustawia jego dane i wywołuje mutacjęupsertUser
, aby utworzyć lub zaktualizować informacje o użytkowniku w bazie danych.handleGetCurrentUser
: pobiera profil bieżącego użytkownika za pomocą zapytaniagetCurrentUser
, które zwraca opinie i ulubione filmy użytkownika.
Jak to działa
Teraz w pasku nawigacyjnym kliknij przycisk „Zaloguj się przez Google”. Możesz zalogować się za pomocą emulatora Uwierzytelniania Firebase. Po zalogowaniu się kliknij „Mój profil”. Na razie będzie pusty, ale masz już podstawy do obsługi danych użytkowników w swojej aplikacji.
7. Implementacja interakcji z użytkownikiem
W tej sekcji zaimplementujesz interakcje z użytkownikami w aplikacji do zamieszczania opinii o filmach, aby umożliwić im zarządzanie ulubionymi filmami oraz zamieszczanie i usuwanie opinii.
Implementacja łączy
- Otwórz
mutations.gql
wdataconnect/movie-connector/
. - Dodaj te mutacje, aby obsługiwać dodawanie filmów do ulubionych:
# 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 })
}
Podsumowanie:
userId_expr: "auth.uid"
: Używaauth.uid
, który jest dostarczany bezpośrednio przez Uwierzytelnianie Firebase, co zapewnia, że dostęp do danych i ich modyfikacja są możliwe tylko dla uwierzytelnionego użytkownika.
- Następnie otwórz
queries.gql
wdataconnect/movie-connector/
. - Dodaj to zapytanie, aby sprawdzić, czy film jest oznaczony jako ulubiony:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
Podsumowanie:
auth.uid
: zapewnia bezpieczny dostęp do danych użytkownika za pomocą Uwierzytelniania Firebase.favorite_movie
: sprawdza tabelę złączeniafavorite_movies
, aby sprawdzić, czy dany film jest oznaczony jako ulubiony przez bieżącego użytkownika.
Integracja zapytań w aplikacji internetowej
- W pliku
MovieService
(app/src/lib/MovieService.tsx
) odkomentuj te importy:
import { addFavoritedMovie, deleteFavoritedMovie, getIfFavoritedMovie } from "@movie/dataconnect";
- Zamień funkcje
handleAddFavoritedMovie
,handleDeleteFavoritedMovie
ihandleGetIfFavoritedMovie
na ten kod:
// 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;
}
};
Podsumowanie:
handleAddFavoritedMovie
ihandleDeleteFavoritedMovie
: użyj mutacji, aby bezpiecznie dodać film do ulubionych lub usunąć go z ulubionych.handleGetIfFavoritedMovie
: korzysta z zapytaniagetIfFavoritedMovie
, aby sprawdzić, czy film został oznaczony przez użytkownika jako ulubiony.
Jak to działa
Teraz możesz dodawać filmy do ulubionych lub usuwać je z listy ulubionych, klikając ikonę serca na karcie filmu i na stronie z informacjami o filmie. Dodatkowo na stronie profilu możesz wyświetlić ulubione filmy.
Wdrażanie opinii użytkowników
Następnie wdrożysz w aplikacji sekcję do zarządzania opiniami użytkowników.
Implementacja łączy
- W
mutations.gql
(dataconnect/movie-connector/mutations.gql
): dodaj te mutacje:
# 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 })
}
Podsumowanie:
userId_expr: "auth.uid"
: zapewnia, że opinie są powiązane z uwierzytelnionym użytkownikiem.reviewDate_date: { today: true }
: automatycznie generuje bieżącą datę opinii za pomocą DataConnect, eliminując potrzebę ręcznego wprowadzania danych.
Integracja zapytań w aplikacji internetowej
- W pliku
MovieService
(app/src/lib/MovieService.tsx
) odkomentuj te importy:
import { addReview, deleteReview } from "@movie/dataconnect";
- Zastąp funkcje
handleAddReview
ihandleDeleteReview
tym kodem:
// 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;
}
};
Podsumowanie:
handleAddReview
: wywołuje mutacjęaddReview
, aby dodać opinię o określonym filmie, bezpiecznie łącząc ją z uwierzytelnionym użytkownikiem.handleDeleteReview
: używa za pomocą zapytaniadeleteReview
do usunięcia recenzji filmu przez uwierzytelnionego użytkownika.
Jak to działa
Użytkownicy mogą teraz zamieszczać opinie o filmach na stronie z informacjami o filmie. Mogą też przeglądać i usuwać swoje opinie na stronie profilu, co daje im pełną kontrolę nad interakcjami z aplikacją.
8. Filtry zaawansowane i dopasowywanie częściowe tekstu
W tej sekcji zaimplementujesz zaawansowane funkcje wyszukiwania, które pozwolą użytkownikom wyszukiwać filmy na podstawie różnych ocen i lat wydania, filtrować według gatunków i tagów, przeprowadzać częściowe dopasowanie tekstu w tytułach lub opisach, a nawet łączyć kilka filtrów, aby uzyskać dokładniejsze wyniki.
Implementacja łączy
- Otwórz
queries.gql
wdataconnect/movie-connector/
. - Dodaj to zapytanie, aby obsługiwać różne funkcje wyszukiwania:
# 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
}
}
}
Podsumowanie:
- Operator
_and
: umożliwia połączenie wielu warunków w jednym zapytaniu, co pozwala filtrować wyniki wyszukiwania według kilku pól, np.releaseYear
,rating
igenre
. - Operator
contains
: wyszukiwanie częściowych dopasowań tekstowych w polach. W tym zapytaniu szuka dopasowań w strumieniachtitle
,description
,name
lubreviewText
. - Klauzula
where
: określa warunki filtrowania danych. Każda sekcja (filmy, aktorzy, recenzje) używa klauzuliwhere
, aby określić konkretne kryteria wyszukiwania.
Integracja zapytań w aplikacji internetowej
- W pliku
MovieService
(app/src/lib/MovieService.tsx
) odkomentuj te importy:
import { searchAll, SearchAllData } from "@movie/dataconnect";
- Zastąp funkcję
handleSearchAll
tym kodem:
// 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;
}
};
Podsumowanie:
handleSearchAll
: ta funkcja używa zapytaniasearchAll
do przeszukiwania na podstawie danych wejściowych użytkownika, filtrując wyniki według takich parametrów jak rok, ocena, gatunek i częściowe dopasowanie tekstu.
Jak to działa
Otwórz stronę „Szukanie zaawansowane” z poziomu paska nawigacyjnego w aplikacji internetowej. Teraz możesz wyszukiwać filmy, aktorów i recenzje, korzystając z różnych filtrów i danych wejściowych, aby uzyskać szczegółowe i dopasowane wyniki wyszukiwania.
9. Opcjonalnie: wdrożenie w chmurze (wymagane rozliczeń)
Po przeprowadzeniu iteracji w lokalnym środowisku programistycznym nadszedł czas na wdrożenie schematu, danych i zapytań na serwer. Możesz to zrobić za pomocą rozszerzenia Firebase Data Connect w VS Code lub wiersza poleceń Firebase.
Dodawanie aplikacji internetowej w konsoli Firebase
- Utwórz aplikację internetową w konsoli Firebase i zapisz identyfikator aplikacji.
- Skonfiguruj aplikację internetową w konsoli Firebase, klikając „Dodaj aplikację”. Na razie możesz zignorować konfigurację pakietu SDK, ale pamiętaj o wygenerowanym obiekcie
firebaseConfig
. - Zastąp tekst
firebaseConfig
w plikuapp/src/lib/firebase.tsx
:
const firebaseConfig = { apiKey: "API_KEY", authDomain: "PROJECT_ID.firebaseapp.com", projectId: "PROJECT_ID", storageBucket: "PROJECT_ID.appspot.com", messagingSenderId: "SENDER_ID", appId: "APP_ID" };
- Utwórz aplikację internetową: w folderze
app
użyj Vite do utworzenia aplikacji internetowej na potrzeby wdrożenia na serwerze:
cd app npm run build
Konfigurowanie uwierzytelniania Firebase w konsoli
- Konfigurowanie Uwierzytelniania Firebase z logowaniem Google
- (Opcjonalnie) Zezwól na domeny w ramach (Uwierzytelniania Firebase) [https://firebase.google.com/docs/auth/web/hosting] w konsoli projektu (np.
http://127.0.0.1
):
- W ustawieniach uwierzytelniania wybierz swój projekt i otwórz stronę (Authorized Domains) [https://firebase.google.com/docs/auth/web/hosting]. Kliknij „Dodaj domenę” i dodaj do listy swoją lokalną domenę.
Wdrażanie za pomocą wiersza poleceń Firebase
- W
dataconnect/dataconnect.yaml
sprawdź, czy identyfikator instancji, bazy danych i usługi są zgodne z Twoim projektem:
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"]
- Sprawdź, czy w Twoim projekcie skonfigurowano wiersz poleceń Firebase.
npm i -g firebase-tools
firebase login --reauth
firebase use --add
- Aby wdrożyć, uruchom w terminalu to polecenie:
firebase deploy --only dataconnect,hosting
- Aby porównać zmiany w schemacie, uruchom to polecenie:
firebase dataconnect:sql:diff
- Jeśli zmiany są akceptowalne, zastosuj je za pomocą:
firebase dataconnect:sql:migrate
Twoja instancja Cloud SQL for PostgreSQL zostanie zaktualizowana o ostateczny wdrożony schemat i dane. Stan możesz sprawdzać w konsoli Firebase.
Twoja aplikacja powinna być teraz widoczna na stronie your-project.web.app/
. Aby dodać dane do środowiska produkcyjnego, możesz też w panelu Firebase Data Connect kliknąć Uruchom (produkcja), tak jak w przypadku emulatorów lokalnych.
10. Opcjonalnie: wyszukiwanie wektorów za pomocą Firebase Data Connect
W tej sekcji włączysz wyszukiwanie wektorów w aplikacji z opiniami o filmach za pomocą Firebase Data Connect. Ta funkcja umożliwia wyszukiwanie treści, np. znajdowanie filmów z podobnymi opisami za pomocą wektorów osadzonych.
Aktualizowanie schematu w celu uwzględnienia wbudowanych elementów w polu
- W
dataconnect/schema/schema.gql
dodaj poledescriptionEmbedding
do tabeliMovie
:
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
}
Podsumowanie:
descriptionEmbedding: Vector @col(size:768)
: to pole przechowuje semantyczne zanurzone opisy filmów, co umożliwia wyszukiwanie treści w aplikacji na podstawie wektorów.
Aktywowanie Vertex AI
- Aby skonfigurować interfejsy Vertex AI API w Google Cloud, postępuj zgodnie z przewodnikiem po wymaganiach wstępnych. Ten krok jest niezbędny do obsługi funkcji generowania wektorów dystrybucyjnych i wyszukiwania wektorowego.
- Ponowne wdrożenie schematu, aby aktywować
pgvector
i wyszukiwanie wektorów, klikając opcję Wdróż w wersji produkcyjnej za pomocą rozszerzenia Firebase Data Connect w VSCode.
Wypełnianie bazy danych za pomocą elementów dołączanych
- Otwórz folder
dataconnect
w VSCode i kliknij Uruchom(lokalnie) woptional_vector_embed.gql
, aby wypełnić bazę danych wbudowanymi reprezentacjami filmów.
Dodawanie zapytania do wyszukiwania wektorowego
- Aby przeprowadzić wyszukiwanie wektorowe, w
dataconnect/movie-connector/queries.gql
dodaj to zapytanie:
# 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
}
}
Podsumowanie:
compare_embed
: określa model zanurzania (textembedding-gecko@003
) i tekst wejściowy ($query
) do porównania.method
: określa metodę podobieństwa (L2
), która reprezentuje odległość euklidesową.within
: ogranicza wyszukiwanie do filmów o odległości L2 2 lub mniejszej, skupiając się na treściach o zbliżonych do siebie atrybutach.limit
: ogranicza liczbę zwracanych wyników do 5.
Wdrażanie funkcji wyszukiwania wektorowego w aplikacji
- W pliku
app/src/lib/MovieService.ts
odkomentuj te importy:
Implementacja funkcji wyszukiwania wektorowego w aplikacji
Po skonfigurowaniu schematu i zapytania zintegruj wyszukiwanie wektorów z poziomem usług aplikacji. Dzięki temu możesz wywołać zapytanie wyszukiwania z aplikacji internetowej.
W pliku app/src/lib/
MovieService.ts
odkomentuj te importy z pakietów SDK. Będą one działać jak zwykłe zapytania.
import {
searchMovieDescriptionUsingL2similarity,
SearchMovieDescriptionUsingL2similarityData,
} from "@movie/dataconnect";
Aby zintegrować wyszukiwanie wektorów z aplikacją, dodaj tę funkcję:
// 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;
}
};
Podsumowanie:
searchMoviesByDescription
: ta funkcja wywołuje zapytaniesearchMovieDescriptionUsingL2similarity
, przekazując tekst wejściowy w celu przeprowadzenia wyszukiwania treści na podstawie wektorów.
Jak to działa
Na pasku nawigacyjnym otwórz sekcję „Wyszukiwanie wektorów” i wpisz frazy takie jak „romantyczny i nowoczesny”. Zobaczysz listę filmów pasujących do wyszukiwanych treści. Możesz też otworzyć stronę z informacjami o dowolnym filmie i przejrzeć sekcję podobnych filmów na dole strony.
11. Podsumowanie
Gratulacje! Powinieneś mieć teraz dostęp do aplikacji internetowej. Jeśli chcesz pracować z własnymi danymi filmu, możesz wstawić je za pomocą rozszerzenia FDC, naśladując pliki _insert.gql, lub dodać je w panelu wykonywania usługi Data Connect.