(Opcjonalnie) Prototypowanie i testowanie przy użyciu Firebase Local Emulator Suite
Zanim zaczniesz mówić o tym, jak Twoja aplikacja odczytuje dane z usługi Realtime Database i zapisuje w niej zapisy, przedstawimy zestaw narzędzi, które możesz wykorzystać do prototypowania i testowania funkcji Realtime Database funkcje: Firebase Local Emulator Suite. Jeśli testujesz inne dane optymalizowanie reguł zabezpieczeń lub wyszukiwanie opłacalny sposób interakcji z backendem, który daje możliwość pracy lokalnej bez wdrażania aktywnych usług może być świetnym pomysłem.
Emulator Realtime Database jest częścią interfejsu Local Emulator Suite, który umożliwia aplikacji interakcję z treścią i konfiguracją emulowanej bazy danych a także opcjonalnie emulowane zasoby projektu (funkcje, inne bazy danych, i reguły zabezpieczeń).
Aby użyć emulatora Realtime Database, wystarczy wykonać kilka czynności:
- Dodajesz wiersz kodu do konfiguracji testowej aplikacji, aby połączyć się z emulatorem.
- Uruchomienie
firebase emulators:start
w katalogu głównym projektu lokalnego. - Wykonywanie wywołań z prototypowego kodu aplikacji za pomocą platformy Realtime Database pakietu SDK w zwykły sposób lub za pomocą interfejsu API REST Realtime Database.
Dostępny jest szczegółowy przewodnik dotyczący elementów Realtime Database i Cloud Functions. Warto też zapoznać się z wprowadzeniem do funkcji Local Emulator Suite.
Pobieranie odniesienia do bazy danych
Aby móc odczytywać lub zapisywać dane z bazy danych, musisz mieć instancję
firebase.database.Reference
:
Web
import { getDatabase } from "firebase/database"; const database = getDatabase();
Web
var database = firebase.database();
Zapisywanie danych
Ten dokument zawiera podstawowe informacje o pobieraniu danych oraz ich porządkowaniu i filtrowaniu. danych Firebase.
Dane Firebase są pobierane przez dołączenie odbiornika asynchronicznego do
firebase.database.Reference
Detektor jest aktywowany raz dla
początkowym stanie danych i ponownie po każdej zmianie danych.
Podstawowe operacje zapisu
W przypadku podstawowych operacji zapisu możesz użyć funkcji set()
, aby zapisać dane w określonym
zastępując wszystkie istniejące dane w tej ścieżce. Na przykład kanał społecznościowy
aplikacja do tworzenia blogów może dodać użytkownika z adresem set()
w następujący sposób:
Web
import { getDatabase, ref, set } from "firebase/database"; function writeUserData(userId, name, email, imageUrl) { const db = getDatabase(); set(ref(db, 'users/' + userId), { username: name, email: email, profile_picture : imageUrl }); }
Web
function writeUserData(userId, name, email, imageUrl) { firebase.database().ref('users/' + userId).set({ username: name, email: email, profile_picture : imageUrl }); }
Użycie elementu set()
powoduje zastąpienie danych w określonej lokalizacji, w tym danych podrzędnych
węzłów.
Odczyt danych
Wykrywaj zdarzenia dotyczące wartości
Aby odczytywać dane na ścieżce i nasłuchiwać zmian, użyj funkcji onValue()
w celu obserwacji
zdarzeń. Za pomocą tego zdarzenia możesz odczytywać statyczne zrzuty zawartości
ze ścieżki dostępnej w momencie wystąpienia zdarzenia. Ta metoda
jest wyzwalana raz, gdy dołącza detektor, i ponownie za każdym razem, gdy dane, w tym elementy podrzędne, zostaną zmienione. Wywołanie zwrotne zdarzenia jest przekazywane do zrzutu zawierającego
wszystkich danych w tej lokalizacji, w tym danych podrzędnych. W przypadku braku danych funkcja
migawka zwróci wartość false
, gdy wywołasz exists()
i null
w przypadku wywołania val()
.
W poniższym przykładzie pokazano, jak aplikacja do blogowania społecznościowego pobiera liczba gwiazdek posta z bazy danych:
Web
import { getDatabase, ref, onValue } from "firebase/database"; const db = getDatabase(); const starCountRef = ref(db, 'posts/' + postId + '/starCount'); onValue(starCountRef, (snapshot) => { const data = snapshot.val(); updateStarCount(postElement, data); });
Web
var starCountRef = firebase.database().ref('posts/' + postId + '/starCount'); starCountRef.on('value', (snapshot) => { const data = snapshot.val(); updateStarCount(postElement, data); });
Detektor odbiera obiekt snapshot
zawierający dane w określonym miejscu
tej lokalizacji w bazie danych w momencie wystąpienia zdarzenia. Dane można pobrać
w snapshot
przy użyciu metody val()
.
Odczytaj dane raz
Jednorazowy odczyt danych za pomocą funkcji get()
Pakiet SDK służy do zarządzania interakcjami z serwerami baz danych niezależnie od tego, czy jest online lub offline.
Ogólnie do odczytu aby otrzymywać powiadomienia o aktualizacjach danych z backendu. Detektor metody zmniejszają wykorzystanie zasobów i płatności, są zoptymalizowane pod kątem aby zadbać o jak najlepsze wrażenia użytkowników korzystających z internetu i offline.
Jeśli dane są potrzebne tylko raz, możesz użyć funkcji get()
, aby uzyskać zrzut
z bazy danych. Jeśli z jakiegoś powodu get()
nie może zwrócić serwera
klient sprawdzi pamięć podręczną pamięci lokalnej i zwróci błąd, jeśli
nadal nie znaleziono wartości.
Niepotrzebne użycie get()
może zwiększyć wykorzystanie przepustowości i doprowadzić do utraty
. Można temu zapobiec, korzystając z detektora w czasie rzeczywistym, jak pokazano powyżej.
Web
import { getDatabase, ref, child, get } from "firebase/database"; const dbRef = ref(getDatabase()); get(child(dbRef, `users/${userId}`)).then((snapshot) => { if (snapshot.exists()) { console.log(snapshot.val()); } else { console.log("No data available"); } }).catch((error) => { console.error(error); });
Web
const dbRef = firebase.database().ref(); dbRef.child("users").child(userId).get().then((snapshot) => { if (snapshot.exists()) { console.log(snapshot.val()); } else { console.log("No data available"); } }).catch((error) => { console.error(error); });
Jednorazowe odczytywanie danych z obserwatorem
W niektórych przypadkach możesz chcieć, aby zwracana była wartość z lokalnej pamięci podręcznej
natychmiast, bez sprawdzania aktualizacji na serwerze. W tych
możesz użyć funkcji once()
, aby od razu pobrać dane z pamięci podręcznej dysku lokalnego.
Jest to przydatne w przypadku danych, które trzeba wczytać tylko raz i w pewnym stopniu często się zmieniają lub wymagają aktywnego słuchania. Na przykład aplikacja do blogowania w poprzednich przykładach korzysta z tej metody do wczytywania profilu użytkownika, gdy rozpocznij tworzenie nowego posta:
Web
import { getDatabase, ref, onValue } from "firebase/database"; import { getAuth } from "firebase/auth"; const db = getDatabase(); const auth = getAuth(); const userId = auth.currentUser.uid; return onValue(ref(db, '/users/' + userId), (snapshot) => { const username = (snapshot.val() && snapshot.val().username) || 'Anonymous'; // ... }, { onlyOnce: true });
Web
var userId = firebase.auth().currentUser.uid; return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => { var username = (snapshot.val() && snapshot.val().username) || 'Anonymous'; // ... });
Aktualizowanie lub usuwanie danych
Zaktualizuj określone pola
Jednoczesne zapisywanie do określonych elementów podrzędnych węzła bez zastępowania innych
węzłów podrzędnych, użyj metody update()
.
Wywołując update()
, możesz zaktualizować wartości podrzędne niższego poziomu przez
i podaj ścieżkę dostępu do klucza. Jeśli dane są przechowywane w wielu lokalizacjach na potrzeby skalowania
możesz zaktualizować wszystkie wystąpienia tych danych za pomocą funkcji
rozpowszechnianie danych.
Na przykład aplikacja do obsługi blogów społecznościowych może utworzyć posta i jednocześnie aktualizować do kanału ostatniej aktywności i kanału aktywności użytkownika publikującego za pomocą podobny do tego:
Web
import { getDatabase, ref, child, push, update } from "firebase/database"; function writeNewPost(uid, username, picture, title, body) { const db = getDatabase(); // A post entry. const postData = { author: username, uid: uid, body: body, title: title, starCount: 0, authorPic: picture }; // Get a key for a new Post. const newPostKey = push(child(ref(db), 'posts')).key; // Write the new post's data simultaneously in the posts list and the user's post list. const updates = {}; updates['/posts/' + newPostKey] = postData; updates['/user-posts/' + uid + '/' + newPostKey] = postData; return update(ref(db), updates); }
Web
function writeNewPost(uid, username, picture, title, body) { // A post entry. var postData = { author: username, uid: uid, body: body, title: title, starCount: 0, authorPic: picture }; // Get a key for a new Post. var newPostKey = firebase.database().ref().child('posts').push().key; // Write the new post's data simultaneously in the posts list and the user's post list. var updates = {}; updates['/posts/' + newPostKey] = postData; updates['/user-posts/' + uid + '/' + newPostKey] = postData; return firebase.database().ref().update(updates); }
W tym przykładzie użyto metody push()
do utworzenia w węźle posta posta zawierającego posty dla:
wszystkich użytkowników w organizacji /posts/$postid
i jednocześnie pobierają klucz. Klucz może
a następnie użyć do utworzenia drugiego wpisu w
posty na blogu /user-posts/$userid/$postid
.
Korzystając z tych ścieżek, można wprowadzać zmiany w wielu lokalizacjach jednocześnie
drzewo JSON z pojedynczym wywołaniem update()
, jak w tym przykładzie
utworzy nowy post w obu lokalizacjach. Równoczesne aktualizacje dokonywane w ten sposób
są niepodzielne: wszystkie aktualizacje zakończą się sukcesem, albo wszystkie aktualizacje kończą się niepowodzeniem.
Dodaj zakończone wywołanie zwrotne
Jeśli chcesz się dowiedzieć, kiedy Twoje dane zostały zatwierdzone, możesz dodać
zakończenia. Zarówno set()
, jak i update()
mogą ukończyć opcjonalnie
wywołanie zwrotne, które jest wywoływane po zatwierdzeniu zapisu w bazie danych. Jeśli
połączenie nie powiodło się, wywołanie zwrotne jest przekazywane
obiektu błędu, który wskazuje przyczynę wystąpienia błędu.
Web
import { getDatabase, ref, set } from "firebase/database"; const db = getDatabase(); set(ref(db, 'users/' + userId), { username: name, email: email, profile_picture : imageUrl }) .then(() => { // Data saved successfully! }) .catch((error) => { // The write failed... });
Web
firebase.database().ref('users/' + userId).set({ username: name, email: email, profile_picture : imageUrl }, (error) => { if (error) { // The write failed... } else { // Data saved successfully! } });
Usuń dane
Najprostszym sposobem usunięcia danych jest wywołanie funkcji remove()
w odniesieniu do
lokalizacji danych.
Możesz również usunąć, określając null
jako wartość innego zapisu
operacji, na przykład set()
lub update()
. Tej metody możesz używać,
za pomocą update()
, aby usunąć wiele elementów podrzędnych w pojedynczym wywołaniu interfejsu API.
Odbierz Promise
Aby dowiedzieć się, kiedy dane są przekazywane na serwerze Firebase Realtime Database,
może użyć polecenia
Promise
Zarówno set()
, jak i update()
mogą zwrócić wartość Promise
, dzięki której dowiesz się, kiedy
dla bazy danych jest zatwierdzany zapis.
Odłącz detektory
Wywołania zwrotne są usuwane przez wywołanie metody off()
na Twoim
Dokumentacja bazy danych Firebase.
Możesz usunąć pojedynczy detektor, przekazując go jako parametr do off()
.
Wywołanie off()
w lokalizacji bez argumentów powoduje usunięcie wszystkich detektorów w tym
lokalizacji.
Wywoływanie połączenia off()
w przypadku detektora nadrzędnego
automatycznie usuwać detektory zarejestrowane w węzłach podrzędnych;
Funkcja off()
musi być również wywoływana w przypadku podrzędnych detektorów
, aby usunąć wywołanie zwrotne.
Zapisywanie danych jako transakcji
Podczas pracy z danymi, które mogły zostać uszkodzone w wyniku równoczesnej pracy takich jak liczniki przyrostowe, możesz użyć funkcji operacji transakcji. Do tej operacji możesz dodać funkcję aktualizacji oraz opcjonalnie zakończenia. Funkcja aktualizacji przyjmuje bieżący stan danych jako argument i zwraca nowy pożądany stan, który chcesz zapisać. Jeśli zanim nowa wartość zostanie pomyślnie zapisana w lokalizacji, inny klient funkcja aktualizacji jest wywoływana ponownie z nową, bieżącą wartością, próba zapisu zostanie ponowiona.
Na przykład w przykładowej aplikacji do blogowania społecznościowego użytkownicy mogą oznaczanie postów gwiazdką i usuwanie gwiazdek oraz śledzenie liczby przyznanych gwiazdek w następujący sposób:
Web
import { getDatabase, ref, runTransaction } from "firebase/database"; function toggleStar(uid) { const db = getDatabase(); const postRef = ref(db, '/posts/foo-bar-123'); runTransaction(postRef, (post) => { if (post) { if (post.stars && post.stars[uid]) { post.starCount--; post.stars[uid] = null; } else { post.starCount++; if (!post.stars) { post.stars = {}; } post.stars[uid] = true; } } return post; }); }
Web
function toggleStar(postRef, uid) { postRef.transaction((post) => { if (post) { if (post.stars && post.stars[uid]) { post.starCount--; post.stars[uid] = null; } else { post.starCount++; if (!post.stars) { post.stars = {}; } post.stars[uid] = true; } } return post; }); }
Użycie transakcji zapobiega nieprawidłowemu liczeniu gwiazdek w przypadku większej liczby Użytkownicy oznaczali gwiazdką tego samego posta w tym samym czasie lub klient miał nieaktualne dane. Jeśli transakcja została odrzucona, serwer zwraca bieżącą wartość klientowi, co powoduje ponowne uruchomienie transakcji zaktualizowanej wartości. Powtarza się do momentu zaakceptowania transakcji lub jej przerwania transakcji.
Atomic przyrosty po stronie serwera
W powyższym przypadku użycia zapisujemy w bazie danych 2 wartości: identyfikator użytkownik, który oznacza post lub oznaczenie gwiazdką posta, i zwiększona liczba gwiazdek. Jeśli że użytkownik oznaczy post gwiazdką, możemy użyć przyrostu atomowego zamiast transakcji.
Web
function addStar(uid, key) { import { getDatabase, increment, ref, update } from "firebase/database"; const dbRef = ref(getDatabase()); const updates = {}; updates[`posts/${key}/stars/${uid}`] = true; updates[`posts/${key}/starCount`] = increment(1); updates[`user-posts/${key}/stars/${uid}`] = true; updates[`user-posts/${key}/starCount`] = increment(1); update(dbRef, updates); }
Web
function addStar(uid, key) { const updates = {}; updates[`posts/${key}/stars/${uid}`] = true; updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1); updates[`user-posts/${key}/stars/${uid}`] = true; updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1); firebase.database().ref().update(updates); }
Ten kod nie korzysta z operacji transakcji, więc nie pobiera automatycznie w przypadku wystąpienia konfliktu aktualizacji uruchom ponownie system. Ponieważ jednak operacja przyrostu odbywa się bezpośrednio na serwerze bazy danych, nie występuje konflikt.
Jeśli chcesz wykrywać i odrzucać konflikty dotyczące aplikacji, na przykład w postach, które zostały już wcześniej oznaczone gwiazdką, należy napisać niestandardowy dla konkretnego przypadku użycia.
Praca z danymi w trybie offline
Jeśli klient utraci połączenie sieciowe, aplikacja będzie nadal działać .
Każdy klient połączony z bazą danych Firebase ma własną wersję wewnętrzną wszystkich aktywnych danych. Podczas zapisywania danych są one zapisywane w tej wersji lokalnej . Klient Firebase następnie synchronizuje te dane ze zdalną bazą danych. z serwerami Google i innymi klientami w ramach „najlepszych starań”, podstaw.
W rezultacie wszystkie zapisy w bazie danych wywołują zdarzenia lokalne natychmiast, przed jakiekolwiek dane są zapisywane na serwerze. Oznacza to, że aplikacja pozostaje niezależnie od opóźnienia sieciowego czy połączenia.
Po przywróceniu połączenia aplikacja otrzyma odpowiedni zestaw zdarzeń, aby klient synchronizował się z bieżącym stanem serwera bez konieczności napisać dowolny niestandardowy kod.
Więcej informacji o zachowaniu użytkowników offline Więcej informacji o możliwościach pracy online i offline