Dzięki Cloud Functions możesz obsługiwać zdarzenia
w Bazie danych czasu rzeczywistego Firebase bez konieczności aktualizowania kodu klienta.
Dzięki Cloud Functions możesz uruchamiać operacje w bazie danych czasu rzeczywistego z pełnymi uprawnieniami administracyjnymi i zadbać o to, aby każda zmiana w bazie danych czasu rzeczywistego była przetwarzana osobno. Zmiany w Bazie danych czasu rzeczywistego Firebase możesz wprowadzać za pomocą narzędzia DataSnapshot
lub pakietu Admin SDK.
W typowym cyklu życia funkcja Bazy danych czasu rzeczywistego Firebase wykonuje te czynności:
- Oczekiwanie na zmiany konkretnej lokalizacji Bazy danych czasu rzeczywistego.
- Jest aktywowany, gdy zdarzenie występuje i wykonuje swoje zadania (przykładowe przypadki użycia znajdziesz w sekcji Co mogę zrobić przy użyciu Cloud Functions?).
- Odbiera obiekt danych zawierający zrzut danych przechowywanych w określonym dokumencie.
Aktywowanie funkcji Bazy danych czasu rzeczywistego
Możesz tworzyć nowe funkcje dla zdarzeń w Bazie danych czasu rzeczywistego za pomocą functions.database
. Aby kontrolować, kiedy funkcja się aktywuje, określ jeden z modułów obsługi zdarzeń i określ ścieżkę Bazy danych czasu rzeczywistego, do której będzie nasłuchiwać zdarzeń.
Ustawianie modułu obsługi zdarzeń
Funkcje umożliwiają obsługę zdarzeń Bazy danych czasu rzeczywistego na 2 poziomach dokładności. Możesz nasłuchiwać tylko zdarzeń tworzenia, aktualizowania lub usuwania bądź nasłuchiwać dowolnej zmiany ścieżki. Cloud Functions obsługuje te moduły obsługi zdarzeń w bazie danych czasu rzeczywistego:
onWrite()
, który jest wyzwalany, gdy dane są tworzone, aktualizowane lub usuwane w bazie danych czasu rzeczywistego.onCreate()
, który jest wyzwalany po utworzeniu nowych danych w bazie danych czasu rzeczywistego.onUpdate()
, który jest wyzwalany po zaktualizowaniu danych w Bazie danych czasu rzeczywistego .onDelete()
, które jest aktywowane, gdy dane zostaną usunięte z Bazy danych czasu rzeczywistego .
Podaj instancję i ścieżkę
Aby kontrolować, kiedy i gdzie Twoja funkcja ma się aktywować, wywołaj metodę ref(path)
w celu określenia ścieżki i opcjonalnie wskaż 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ą funkcję do obsługi zapisów na 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 wykonywanych pod nią. Jeśli ustawisz ścieżkę funkcji jako /foo/bar
, będzie ona dopasowywana do zdarzeń w obu tych lokalizacjach:
/foo/bar
/foo/bar/baz/really/deep/path
W obu tych przypadkach Firebase interpretuje, że zdarzenie ma miejsce /foo/bar
, a dane zdarzenia zawierają stare i nowe dane z /foo/bar
. Jeśli dane zdarzeń są duże, rozważ użycie wielu funkcji na dalszych ścieżkach zamiast jednej funkcji w pobliżu poziomu głównego bazy danych. Aby uzyskać najlepszą skuteczność, proś o dane tylko na najgłębszym możliwym poziomie.
Komponent ścieżki możesz podać jako symbol wieloznaczny, umieszczając w nawiasach klamrowych nawiasy klamrowe. Komponent ref('foo/{bar}')
pasuje do dowolnego elementu podrzędnego elementu /foo
. Wartości tych komponentów ścieżki z symbolami wieloznacznymi są dostępne w obiekcie EventContext.params
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. Wstawienie
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
2 razy pasuje do ścieżki "/foo/{bar}"
: raz z "hello": "world"
i jeszcze raz z "firebase": "functions"
.
Obsługa danych zdarzenia
W przypadku obsługi zdarzenia Bazy danych czasu rzeczywistego zwracanym obiektem danych jest DataSnapshot
.
W przypadku zdarzeń onWrite
lub onUpdate
pierwszym parametrem jest obiekt Change
zawierający 2 zrzuty obrazujące stan danych przed zdarzeniem wywołującym i po nim. W przypadku zdarzeń onCreate
i onDelete
zwracany obiekt danych to migawka danych utworzonych lub usuniętych.
W tym przykładzie funkcja pobiera zrzut dla określonej ścieżki, zamienia ciąg znaków w tej lokalizacji na wielkie litery i zapisuje ten 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); });
Uzyskiwanie dostępu do informacji uwierzytelniających użytkowników
W usługach EventContext.auth
i EventContext.authType
możesz uzyskać dostęp do informacji o użytkowniku, który uruchomił funkcję, w tym do jego uprawnień. Może to być przydatne do egzekwowania reguł zabezpieczeń, ponieważ umożliwia funkcji wykonywania 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 też wykorzystać informacje uwierzytelniające użytkownika do „podszywania się” pod użytkownika i wykonywania operacji zapisu w jego imieniu. Aby uniknąć problemów z równoczesnością, usuń wystąpienie aplikacji, jak pokazano poniżej:
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 umożliwia sprawdzenie, co zostało zapisane w bazie danych czasu rzeczywistego przed zdarzeniem. Właściwość before
zwraca wartość DataSnapshot
, gdzie wszystkie metody (np. val()
i exists()
) odwołują się do poprzedniej wartości. Możesz ją odczytać ponownie, używając pierwotnego elementu DataSnapshot
lub właściwości after
. Ta właściwość w dowolnym elemencie Change
to inna właściwość DataSnapshot
reprezentująca stan danych po wystąpieniu zdarzenia.
Na przykład przy użyciu właściwości before
możesz mieć pewność, że podczas tworzenia funkcja pisze tylko wielkie litery w tekście:
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);
});