Dzięki Cloud Functions możesz obsługiwać zdarzenia w Firebase Realtime Database bez konieczności aktualizowania kodu klienta. Cloud Functions umożliwia wykonywanie operacji Realtime Database z pełnymi uprawnieniami administracyjnymi i zapewnia, że każda zmiana w Realtime Database jest przetwarzana oddzielnie. Możesz wprowadzać Firebase Realtime Database zmiany za pomocą migawki danych lub pakietu Admin SDK.
W typowym cyklu życia funkcja Firebase Realtime Database wykonuje te czynności:
- Czeka na zmiany w określonej Realtime Database ścieżce.
- Uruchamia się, gdy wystąpi zdarzenie, i wykonuje swoje zadania.
- Otrzymuje obiekt danych, który zawiera zrzut danych przechowywanych w tej ścieżce.
Funkcję możesz aktywować w odpowiedzi na zapisywanie, tworzenie, aktualizowanie lub usuwanie węzłów bazy danych w Firebase Realtime Database. Aby określić, kiedy funkcja ma się uruchamiać, podaj jeden z modułów obsługi zdarzeń i ścieżkę Realtime Database, na której będzie nasłuchiwać zdarzeń.
Ustawianie lokalizacji funkcji
Odległość między lokalizacją instancji Realtime Database a lokalizacją funkcji może powodować znaczne opóźnienia sieci. Niezgodność między regionami może też spowodować niepowodzenie wdrożenia. Aby uniknąć takich sytuacji, określ lokalizację funkcji, tak aby była zgodna z lokalizacją instancji bazy danych.
Obsługa zdarzeń Realtime Database
Funkcje umożliwiają obsługę Realtime Databasezdarzeń na 2 poziomach szczegółowości: możesz nasłuchiwać tylko zdarzeń zapisu, tworzenia, aktualizacji lub usuwania albo nasłuchiwać dowolnych zmian w odniesieniu.
Dostępne są te moduły obsługi zdarzeń Realtime Database:
onValueWritten()
Aktywowany, gdy dane są tworzone, aktualizowane lub usuwane w Realtime Database.onValueCreated()
Wywoływane tylko wtedy, gdy dane są tworzone w Realtime Database.onValueUpdated()
Aktywowane tylko wtedy, gdy dane są aktualizowane w Realtime Database.onValueDeleted()
Wyzwalany tylko wtedy, gdy dane są usuwane w Realtime Database.
on_value_written()
Aktywowany, gdy dane są tworzone, aktualizowane lub usuwane w Realtime Database.on_value_created()
Wywoływane tylko wtedy, gdy dane są tworzone w Realtime Database.on_value_updated()
Aktywowane tylko wtedy, gdy dane są aktualizowane w Realtime Database.on_value_deleted()
Wyzwalany tylko wtedy, gdy dane są usuwane w Realtime Database.
Importowanie wymaganych modułów
W źródle funkcji musisz zaimportować moduły pakietu SDK, których chcesz używać. W tym przykładzie konieczne jest zaimportowanie modułów HTTP i Realtime Database oraz modułu Firebase Admin SDK do zapisywania w Realtime Database.
// The Cloud Functions for Firebase SDK to setup triggers and logging.
const {onRequest} = require("firebase-functions/v2/https");
const {onValueCreated} = require("firebase-functions/v2/database");
const {logger} = require("firebase-functions");
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
admin.initializeApp();
# The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
from firebase_functions import db_fn, https_fn
# The Firebase Admin SDK to access the Firebase Realtime Database.
from firebase_admin import initialize_app, db
app = initialize_app()
Określanie instancji i ścieżki
Aby określić, kiedy i gdzie funkcja ma się uruchamiać, skonfiguruj ją, podając ścieżkę i opcjonalnie Realtime Database instancję. Jeśli nie określisz instancji, funkcja będzie nasłuchiwać wszystkich instancji Realtime Database w regionie funkcji. Możesz też określić wzorzec instancji Realtime Database, aby wdrożyć go w wybranym podzbiorze instancji w tym samym regionie.
Przykład:
// All Realtime Database instances in default function region us-central1 at path "/user/{uid}" // There must be at least one Realtime Database present in us-central1. const onWrittenFunctionDefault = onValueWritten("/user/{uid}", (event) => { // … }); // Instance named "my-app-db-2", at path "/user/{uid}". // The "my-app-db-2" instance must exist in this region. const OnWrittenFunctionInstance = onValueWritten( { ref: "/user/{uid}", instance: "my-app-db-2" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (event) => { // … } ); // Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com. // There must be at least one Realtime Database with "my-app-db-*" prefix in this region. const onWrittenFunctionInstance = onValueWritten( { ref: "/user/{uid=*@gmail.com}", instance: "my-app-db-*" // This example assumes us-central1, but to set location: // region: "europe-west1" }, (event) => { // … } );
# All Realtime Database instances in default function region us-central1 at path "/user/{uid}"
# There must be at least one Realtime Database present in us-central1.
@db_fn.on_value_written(r"/user/{uid}")
def onwrittenfunctiondefault(event: db_fn.Event[db_fn.Change]):
# ...
pass
# Instance named "my-app-db-2", at path "/user/{uid}".
# The "my-app-db-2" instance must exist in this region.
@db_fn.on_value_written(
reference=r"/user/{uid}",
instance="my-app-db-2",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
# ...
pass
# Instance with "my-app-db-" prefix, at path "/user/{uid}", where uid ends with @gmail.com.
# There must be at least one Realtime Database with "my-app-db-*" prefix in this region.
@db_fn.on_value_written(
reference=r"/user/{uid=*@gmail.com}",
instance="my-app-db-*",
# This example assumes us-central1, but to set location:
# region="europe-west1",
)
def on_written_function_instance(event: db_fn.Event[db_fn.Change]):
# ...
pass
Te parametry kierują funkcję do obsługi zapisów w określonej ścieżce w ramach instancji Realtime Database.
Specyfikacje ścieżek pasują do wszystkich zapisów, które dotyczą ścieżki, w tym zapisów, które występują w dowolnym miejscu poniżej niej. Jeśli ścieżka funkcji to /foo/bar
, będzie ona pasować do zdarzeń w obu tych lokalizacjach:
/foo/bar
/foo/bar/baz/really/deep/path
W obu przypadkach Firebase interpretuje, że zdarzenie występuje w momencie /foo/bar
, a dane zdarzenia zawierają stare i nowe dane w momencie /foo/bar
. Jeśli dane zdarzenia mogą być duże, rozważ użycie wielu funkcji na głębszych ścieżkach zamiast jednej funkcji w pobliżu katalogu głównego bazy danych. Aby uzyskać najlepszą wydajność, wysyłaj prośby o dane tylko na najniższym możliwym poziomie.
Używanie symboli wieloznacznych i przechwytywanie
Do rejestrowania możesz używać {key}
, {key=*}
, {key=prefix*}
, {key=*suffix}
. *
, prefix*
, *suffix
w przypadku symboli wieloznacznych w jednym segmencie.
Uwaga: symbol **
oznacza wielosegmentowe symbole wieloznaczne, które nie są obsługiwane przez Realtime Database.
Zobacz Omówienie wzorców ścieżek.
Wieloznaczność ścieżki Możesz określić składnik ścieżki jako symbol wieloznaczny:
- Używanie gwiazdki,
*
Na przykładfoo/*
pasuje do wszystkich elementów podrzędnych na poziomie 1 hierarchii węzłów poniżejfoo/
. - Używanie segmentu zawierającego dokładnie gwiazdkę
*
. Na przykładfoo/app*-us
pasuje do wszystkich segmentów podrzędnych poniżejfoo/
z prefiksemapp
i sufiksem-us
.
Ścieżki z symbolami wieloznacznymi mogą pasować do wielu zdarzeń, np. z jednego zapisu. Wstawka
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
pasuje do ścieżki "/foo/*"
2 razy: raz z "hello": "world"
i raz z "firebase": "functions"
.
Rejestrowanie ścieżki Dopasowania ścieżek możesz przechwytywać do nazwanych zmiennych, które będą używane w kodzie funkcji (np. /user/{uid}
, /user/{uid=*-us}
).
Wartości zmiennych przechwytywania są dostępne w obiekcie database.DatabaseEvent.params funkcji.
Symbole wieloznaczne w instancjach Możesz też określić komponent instancji za pomocą symboli wieloznacznych. Symbol wieloznaczny instancji może mieć prefiks, sufiks lub oba te elementy (np. my-app-*-prod
).
Symbole wieloznaczne i odwołania do przechwyconych wartości
W przypadku Cloud Functions (2 generacji) i Realtime Database wzorca można używać podczas określania ref
i instance
. Każdy interfejs wyzwalacza będzie miał te opcje określania zakresu funkcji:
Określanie ref |
Określanie instance |
Zachowanie |
---|---|---|
Pojedynczy (/foo/bar ) |
Nie określono | Ogranicza zakres działania do wszystkich instancji w regionie funkcji. |
Pojedynczy (/foo/bar ) |
Pojedynczy (‘my-new-db' ) |
Obsługa zakresów w konkretnej instancji w regionie funkcji. |
Pojedynczy (/foo/bar ) |
Wzór (‘inst-prefix*' ) |
Ogranicza zakres działania funkcji do wszystkich instancji pasujących do wzorca w regionie funkcji. |
Wzór (/foo/{bar} ) |
Nie określono | Ogranicza zakres działania do wszystkich instancji w regionie funkcji. |
Wzór (/foo/{bar} ) |
Pojedynczy (‘my-new-db' ) |
Obsługa zakresów w konkretnej instancji w regionie funkcji. |
Wzór (/foo/{bar} ) |
Wzór (‘inst-prefix*' ) |
Ogranicza zakres działania funkcji do wszystkich instancji pasujących do wzorca w regionie funkcji. |
Obsługa danych zdarzenia
Gdy zostanie wywołane zdarzenie Realtime Database, do funkcji obsługi przekazywany jest obiekt Event
.
Ten obiekt ma właściwość data
, która w przypadku zdarzeń tworzenia i usuwania zawiera migawkę utworzonych lub usuniętych danych.
W tym przykładzie funkcja pobiera dane ze ścieżki, do której się odwołuje, przekształca ciąg znaków w tej lokalizacji na wielkie litery i zapisuje zmodyfikowany ciąg znaków w bazie danych:
// Listens for new messages added to /messages/:pushId/original and creates an
// uppercase version of the message to /messages/:pushId/uppercase
// for all databases in 'us-central1'
exports.makeuppercase = onValueCreated(
"/messages/{pushId}/original",
(event) => {
// Grab the current value of what was written to the Realtime Database.
const original = event.data.val();
logger.log("Uppercasing", event.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing
// asynchronous tasks inside a function, such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the
// Realtime Database returns a Promise.
return event.data.ref.parent.child("uppercase").set(uppercase);
},
);
@db_fn.on_value_created(reference="/messages/{pushId}/original")
def makeuppercase(event: db_fn.Event[Any]) -> None:
"""Listens for new messages added to /messages/{pushId}/original and
creates an uppercase version of the message to /messages/{pushId}/uppercase
"""
# Grab the value that was written to the Realtime Database.
original = event.data
if not isinstance(original, str):
print(f"Not a string: {event.reference}")
return
# Use the Admin SDK to set an "uppercase" sibling.
print(f"Uppercasing {event.params['pushId']}: {original}")
upper = original.upper()
parent = db.reference(event.reference).parent
if parent is None:
print("Message can't be root node.")
return
parent.child("uppercase").set(upper)
Odczytywanie poprzedniej wartości
W przypadku zdarzeń write
lub update
właściwość data
jest obiektem Change
, który zawiera 2 migawki przedstawiające stan danych przed zdarzeniem wywołującym i po nim.
Obiekt Change
ma właściwość before
, która umożliwia sprawdzenie, co zostało zapisane w Realtime Database przed zdarzeniem, oraz właściwość after
, która reprezentuje stan danych po zdarzeniu.
Na przykład właściwość before
może służyć do zapewnienia, że funkcja będzie przekształcać tekst na wielkie litery tylko podczas jego pierwszego tworzenia:
exports makeUppercase = onValueWritten("/messages/{pushId}/original", (event) => { // Only edit data when it is first created. if (event.data.before.exists()) { return null; } // Exit when the data is deleted. if (!event.data.after.exists()) { return null; } // Grab the current value of what was written to the Realtime Database. const original = event.data.after.val(); console.log('Uppercasing', event.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 event.data.after.ref.parent.child('uppercase').set(uppercase); });
@db_fn.on_value_written(reference="/messages/{pushId}/original")
def makeuppercase2(event: db_fn.Event[db_fn.Change]) -> None:
"""Listens for new messages added to /messages/{pushId}/original and
creates an uppercase version of the message to /messages/{pushId}/uppercase
"""
# Only edit data when it is first created.
if event.data.before is not None:
return
# Exit when the data is deleted.
if event.data.after is None:
return
# Grab the value that was written to the Realtime Database.
original = event.data.after
if not hasattr(original, "upper"):
print(f"Not a string: {event.reference}")
return
# Use the Admin SDK to set an "uppercase" sibling.
print(f"Uppercasing {event.params['pushId']}: {original}")
upper = original.upper()
parent = db.reference(event.reference).parent
if parent is None:
print("Message can't be root node.")
return
parent.child("uppercase").set(upper)