Avec Cloud Functions, vous pouvez gérer les événements dans Firebase Realtime Database sans avoir à mettre à jour le code client. Cloud Functions vous permet d'exécuter des opérations Realtime Database avec des droits d'administrateur complets et garantit que chaque modification de Realtime Database est traitée individuellement. Vous pouvez apporter des modifications Firebase Realtime Database via l'instantané de données ou via le SDK Admin.
Dans un cycle de vie typique, une fonction Firebase Realtime Database effectue les opérations suivantes:
- Attend les modifications apportées à un chemin Realtime Database particulier.
- Se déclenche lorsqu'un événement se produit et exécute ses tâches.
- Reçoit un objet de données qui contient un instantané des données stockées à ce chemin d'accès.
Vous pouvez déclencher une fonction en réponse à l'écriture, à la création, à la mise à jour ou à la suppression de nœuds de base de données dans Firebase Realtime Database. Pour contrôler le moment où la fonction se déclenche, spécifiez l'un des gestionnaires d'événements et le chemin d'accès Realtime Database où elle écoutera les événements.
Définir l'emplacement de la fonction
La distance entre l'emplacement d'une instance Realtime Database et l'emplacement de la fonction peut créer une latence réseau importante. De plus, une incohérence entre les régions peut entraîner un échec du déploiement. Pour éviter ces situations, spécifiez l'emplacement de la fonction afin qu'il corresponde à l'emplacement de l'instance de base de données.
Gérer les événements Realtime Database
Cloud Functions vous permet de gérer les événements Realtime Database à deux niveaux de spécificité. Vous pouvez écouter uniquement les événements d'écriture, de création, de mise à jour ou de suppression, ou bien écouter toute modification apportée à une référence.
Les gestionnaires suivants permettent de répondre aux événements Realtime Database:
Node.js
onValueWritten()
Déclenché lors de la création, de la mise à jour ou de la suppression de données dans Realtime Database.onValueCreated()
Ne se déclenche que lorsque des données sont créées dans Realtime Database.onValueUpdated()
Ne se déclenche que lorsque les données sont mises à jour dans Realtime Database.onValueDeleted()
Ne se déclenche que lorsque des données sont supprimées dans Realtime Database.
Python
on_value_written()
Déclenché lors de la création, de la mise à jour ou de la suppression de données dans Realtime Database.on_value_created()
Ne se déclenche que lorsque des données sont créées dans Realtime Database.on_value_updated()
Ne se déclenche que lorsque les données sont mises à jour dans Realtime Database.on_value_deleted()
Ne se déclenche que lorsque des données sont supprimées dans Realtime Database.
Importer les modules requis
Dans le code source de votre fonction, vous devez importer les modules de SDK que vous souhaitez utiliser. Pour cet exemple, vous devez importer les modules HTTP et Realtime Database, ainsi que le module Firebase Admin SDK pour écrire dans Realtime Database.
Node.js
// 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();
Python
# 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()
Spécifier l'instance et le chemin d'accès
Pour contrôler le moment et le lieu du déclenchement de votre fonction, configurez-la avec un chemin d'accès et éventuellement une instance Realtime Database. Si vous ne spécifiez pas d'instance, la fonction écoute toutes les instances Realtime Database de la région de la fonction. Vous pouvez également spécifier un modèle d'instance Realtime Database à déployer sur un sous-ensemble sélectif d'instances dans la même région.
Exemple :
Node.js
// 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) => { // … } );
Python
# 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
Ces paramètres indiquent à votre fonction de gérer les écritures à un certain chemin d'accès dans l'instance Realtime Database.
Les spécifications de chemin d'accès correspondent à toutes les écritures qui touchent un chemin d'accès, y compris les écritures se trouvant en dessous. Si vous définissez le chemin d'accès de votre fonction sur /foo/bar
, il correspond aux événements de ces deux emplacements:
/foo/bar
/foo/bar/baz/really/deep/path
Dans les deux cas, Firebase interprète que l'événement se produit à /foo/bar
et que les données d'événement incluent les anciennes et les nouvelles données se trouvant à /foo/bar
. Si les données d'événement risquent d'être volumineuses, envisagez d'utiliser plusieurs fonctions sur des chemins d'accès plus profonds au lieu d'utiliser une seule fonction près de la racine de votre base de données. Pour des performances optimales, demandez uniquement des données au niveau le plus profond possible.
Caractères génériques et capture
Vous pouvez utiliser {key}
, {key=*}
, {key=prefix*}
et {key=*suffix}
pour la capture. *
, prefix*
et *suffix
pour les caractères génériques à un seul segment.
Remarque: **
représente les caractères génériques multisegments, qui ne sont pas acceptés par Realtime Database.
Consultez Comprendre les formats de chemin d'accès.
Caractère générique de chemin d'accès Vous pouvez spécifier un composant de chemin d'accès en tant que caractère générique:
- à l'aide de l'astérisque
*
. Par exemple,foo/*
correspond à tous les enfants d'un niveau de la hiérarchie des nœuds sousfoo/
. - En utilisant un segment contenant exactement un astérisque,
*
. Par exemple,foo/app*-us
correspond à tous les segments enfants sousfoo/
avec le préfixeapp
et le suffixe-us
.
Les chemins d'accès contenant des caractères génériques peuvent correspondre à plusieurs événements, par exemple d'une seule écriture. Une insertion de
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
correspond au chemin d'accès "/foo/*"
deux fois : une fois avec "hello": "world"
et une autre fois avec "firebase": "functions"
.
Capture de chemin. Vous pouvez capturer les correspondances de chemin d'accès dans des variables nommées à utiliser dans le code de votre fonction (par exemple, /user/{uid}
, /user/{uid=*-us}
).
Les valeurs des variables de capture sont disponibles dans l'objet database.DatabaseEvent.params de votre fonction.
Substitution générique d'instance. Vous pouvez également spécifier un composant d'instance à l'aide de caractères génériques. Un caractère générique d'instance peut comporter un préfixe, un suffixe ou les deux (par exemple, my-app-*-prod
).
Référence sur les caractères génériques et la capture
Avec Cloud Functions (2e génération) et Realtime Database, un format peut être utilisé lors de la spécification de ref
et instance
. Chaque interface de déclencheur propose les options suivantes pour définir le champ d'application d'une fonction:
Spécifier ref |
Spécifier instance |
Comportement |
---|---|---|
Simple (/foo/bar ) |
Ne pas spécifier | Définit le gestionnaire de portée sur toutes les instances de la région de fonction. |
Simple (/foo/bar ) |
Simple (‘my-new-db' ) |
Définit le gestionnaire sur l'instance spécifique de la région de la fonction. |
Simple (/foo/bar ) |
Motif (‘inst-prefix*' ) |
Définit le gestionnaire de portée sur toutes les instances correspondant au modèle dans la région de la fonction. |
Motif (/foo/{bar} ) |
Ne pas spécifier | Définit le gestionnaire de portée sur toutes les instances de la région de fonction. |
Motif (/foo/{bar} ) |
Simple (‘my-new-db' ) |
Définit le gestionnaire sur l'instance spécifique de la région de la fonction. |
Motif (/foo/{bar} ) |
Motif (‘inst-prefix*' ) |
Définit le gestionnaire de portée sur toutes les instances correspondant au modèle dans la région de la fonction. |
Gérer les données d'événement
Lorsqu'un événement Realtime Database se déclenche, il transmet un objet Event
à votre fonction de gestionnaire.
Cet objet possède une propriété data
, qui, pour les événements de création et de suppression, contient un instantané des données créées ou supprimées.
Dans cet exemple, la fonction récupère les données du chemin référencé, convertit la chaîne à cet emplacement en majuscules et écrit cette chaîne modifiée dans la base de données:
Node.js
// 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);
},
);
Python
@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)
Lire la valeur précédente
Pour les événements write
ou update
, la propriété data
est un objet Change
qui contient deux instantanés représentant l'état des données avant et après l'événement déclencheur.
L'objet Change
possède une propriété before
qui vous permet d'inspecter ce qui a été enregistré dans Realtime Database avant l'événement et une propriété after
qui représente l'état des données après l'événement.
Par exemple, la propriété before
peut être utilisée pour s'assurer que la fonction ne met en majuscules le texte que lors de sa première création:
Node.js
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); });
Python
@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)