Dzięki Cloud Functions możesz obsługiwać zdarzenia w bazie danych czasu rzeczywistego Firebase bez konieczności aktualizowania kodu klienta. Cloud Functions umożliwia uruchamianie operacji w bazie danych czasu rzeczywistego z pełnymi uprawnieniami administracyjnymi i gwarantuje, że każda zmiana w bazie danych czasu rzeczywistego jest przetwarzana indywidualnie. Zmiany w Bazie danych czasu rzeczywistego Firebase możesz wprowadzać za pomocą DataSnapshot
lub Admin SDK .
W typowym cyklu życia funkcja Bazy danych czasu rzeczywistego Firebase wykonuje następujące czynności:
- Czeka na zmiany w określonej lokalizacji bazy danych czasu rzeczywistego.
- Wyzwala się, gdy zdarzenie ma miejsce i wykonuje swoje zadania (zobacz Co mogę zrobić z Cloud Functions?, aby zapoznać się z przykładami przypadków użycia).
- Odbiera obiekt danych, który zawiera migawkę danych przechowywanych w określonym dokumencie.
Uruchom funkcję bazy danych czasu rzeczywistego
Twórz nowe funkcje dla zdarzeń bazy danych czasu rzeczywistego za pomocą functions.database
. Aby kontrolować, kiedy funkcja jest wyzwalana, określ jedną z procedur obsługi zdarzeń i określ ścieżkę do bazy danych czasu rzeczywistego, w której będzie nasłuchiwać zdarzeń.
Ustaw obsługę zdarzeń
Funkcje umożliwiają obsługę zdarzeń bazy danych czasu rzeczywistego na dwóch poziomach szczegółowości; możesz nasłuchiwać tylko dla zdarzeń tworzenia, aktualizacji lub usuwania lub możesz nasłuchiwać jakichkolwiek zmian w ścieżce. Cloud Functions obsługuje te procedury obsługi zdarzeń dla bazy danych czasu rzeczywistego:
-
onWrite()
, która jest wyzwalana, gdy dane są tworzone, aktualizowane lub usuwane w bazie danych czasu rzeczywistego. -
onCreate()
, która uruchamia się, gdy nowe dane są tworzone w bazie danych czasu rzeczywistego. -
onUpdate()
, która uruchamia się, gdy dane są aktualizowane w bazie danych czasu rzeczywistego. -
onDelete()
, która uruchamia się, gdy dane są usuwane z bazy danych czasu rzeczywistego .
Określ instancję i ścieżkę
Aby kontrolować, kiedy i gdzie funkcja ma się uruchamiać, wywołaj funkcję ref(path)
w celu określenia ścieżki i opcjonalnie określ instancję bazy danych czasu rzeczywistego za pomocą instance('INSTANCE_NAME')
. Jeśli nie określisz instancji, funkcja zostanie wdrożona w domyślnej instancji Bazy danych czasu rzeczywistego dla projektu Firebase. Na przykład:
- Domyślna instancja bazy danych czasu rzeczywistego:
functions.database.ref('/foo/bar')
- Instancja o nazwie „my-app-db-2”:
functions.database.instance('my-app-db-2').ref('/foo/bar')
Te metody kierują twoją funkcję do obsługi zapisów w określonej ścieżce w instancji bazy danych czasu rzeczywistego. Specyfikacje ścieżki pasują do wszystkich zapisów, które dotykają ścieżki, w tym zapisów, które mają miejsce gdziekolwiek poniżej. Jeśli ustawisz ścieżkę dla swojej funkcji jako /foo/bar
, dopasuje ona zdarzenia w obu tych lokalizacjach:
/foo/bar
/foo/bar/baz/really/deep/path
W obu przypadkach Firebase interpretuje, że zdarzenie ma miejsce w /foo/bar
, a dane zdarzenia obejmują stare i nowe dane w /foo/bar
. Jeśli dane zdarzeń mogą być duże, rozważ użycie wielu funkcji w głębszych ścieżkach zamiast jednej funkcji w pobliżu katalogu głównego bazy danych. Aby uzyskać najlepszą wydajność, żądaj danych tylko na najgłębszym możliwym poziomie.
Możesz określić komponent ścieżki jako symbol wieloznaczny, otaczając go nawiasami klamrowymi; ref('foo/{bar}')
dopasowuje dowolne dziecko /foo
. Wartości tych składników ścieżki z symbolami wieloznacznymi są dostępne w obiekcie EventContext.params
Twojej funkcji. W tym przykładzie wartość jest dostępna jako context.params.bar
.
Ścieżki z symbolami wieloznacznymi mogą pasować do wielu zdarzeń z jednego zapisu. Wkładka z
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
dwukrotnie dopasowuje ścieżkę "/foo/{bar}"
: raz z "hello": "world"
i ponownie z "firebase": "functions"
.
Obsługuj dane zdarzeń
Podczas obsługi zdarzenia bazy danych czasu rzeczywistego zwracanym obiektem danych jest DataSnapshot
. W przypadku zdarzeń onWrite
lub onUpdate
pierwszym parametrem jest obiekt Change
, który zawiera dwie migawki reprezentujące stan danych przed i po zdarzeniu wyzwalającym. W przypadku zdarzeń onCreate
i onDelete
zwracany obiekt danych jest migawką utworzonych lub usuniętych danych.
W tym przykładzie funkcja pobiera migawkę dla określonej ścieżki, konwertuje ciąg w tej lokalizacji na wielkie litery i zapisuje zmodyfikowany ciąg w bazie danych:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
Dostęp do informacji uwierzytelniających użytkownika
Z EventContext.auth
i EventContext.authType
można uzyskać dostęp do informacji o użytkowniku, w tym uprawnień, dla użytkownika, który wyzwolił funkcję. Może to być przydatne do egzekwowania reguł bezpieczeństwa, umożliwiając Twojej funkcji wykonywanie różnych operacji w zależności od poziomu uprawnień użytkownika:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.simpleDbFunction = functions.database.ref('/path')
.onCreate((snap, context) => {
if (context.authType === 'ADMIN') {
// do something
} else if (context.authType === 'USER') {
console.log(snap.val(), 'written by', context.auth.uid);
}
});
Możesz także wykorzystać informacje uwierzytelniające użytkownika, aby „podszywać się” pod użytkownika i wykonywać operacje zapisu w jego imieniu. Pamiętaj, aby usunąć instancję aplikacji, jak pokazano poniżej, aby zapobiec problemom z współbieżnością:
exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const app = admin.initializeApp(appOptions, 'app');
const uppercase = snap.val().toUpperCase();
const ref = snap.ref.parent.child('uppercase');
const deleteApp = () => app.delete().catch(() => null);
return app.database().ref(ref).set(uppercase).then(res => {
// Deleting the app is necessary for preventing concurrency leaks
return deleteApp().then(() => res);
}).catch(err => {
return deleteApp().then(() => Promise.reject(err));
});
});
Odczyt poprzedniej wartości
Obiekt Change
ma właściwość before
, która pozwala sprawdzić, co zostało zapisane w bazie danych czasu rzeczywistego przed zdarzeniem. Właściwość before
zwraca obiekt DataSnapshot
, w którym wszystkie metody (na przykład val()
i exists()
) odwołują się do poprzedniej wartości. Możesz ponownie odczytać nową wartość, używając oryginalnej DataSnapshot
lub odczytując właściwość after
. Ta właściwość dowolnej Change
jest kolejną DataSnapshot
reprezentującą stan danych po wystąpieniu zdarzenia.
Na przykład właściwość before
może być wykorzystana do upewnienia się, że podczas pierwszego tworzenia funkcji tekst jest pisany tylko wielkimi literami:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return change.after.ref.parent.child('uppercase').set(uppercase);
});