Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Déclencheurs de base de données en temps réel

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Avec Cloud Functions, vous pouvez gérer les événements dans la base de données en temps réel Firebase sans avoir à mettre à jour le code client. Cloud Functions vous permet d'exécuter des opérations de base de données en temps réel avec des privilèges administratifs complets et garantit que chaque modification apportée à la base de données en temps réel est traitée individuellement. Vous pouvez apporter des modifications à la base de données en temps réel Firebase via le DataSnapshot ou via le SDK Admin .

Dans un cycle de vie typique, une fonction Firebase Realtime Database effectue les opérations suivantes :

  1. Attend les modifications apportées à un emplacement particulier de la base de données en temps réel.
  2. Se déclenche lorsqu'un événement se produit et exécute ses tâches (voir Que puis-je faire avec Cloud Functions ? pour des exemples de cas d'utilisation).
  3. Reçoit un objet de données qui contient un instantané des données stockées dans le document spécifié.

Déclencher une fonction de base de données en temps réel

Créez de nouvelles fonctions pour les événements de base de données en temps réel avec functions.database . Pour contrôler le moment où la fonction se déclenche, spécifiez l'un des gestionnaires d'événements et spécifiez le chemin de la base de données en temps réel où elle écoutera les événements.

Définir le gestionnaire d'événements

Les fonctions vous permettent de gérer les événements de la base de données en temps réel à deux niveaux de spécificité ; vous pouvez écouter spécifiquement uniquement les événements de création, de mise à jour ou de suppression, ou vous pouvez écouter tout changement de quelque nature que ce soit sur un chemin. Cloud Functions est compatible avec les gestionnaires d'événements suivants pour la base de données en temps réel :

  • onWrite() , qui se déclenche lorsque des données sont créées, mises à jour ou supprimées dans la base de données en temps réel.
  • onCreate() , qui se déclenche lorsque de nouvelles données sont créées dans Realtime Database.
  • onUpdate() , qui se déclenche lorsque les données sont mises à jour dans Realtime Database .
  • onDelete() , qui se déclenche lorsque des données sont supprimées de Realtime Database .

Spécifiez l'instance et le chemin

Pour contrôler quand et où votre fonction doit se déclencher, appelez ref(path) pour spécifier un chemin et spécifiez éventuellement une instance de base de données en temps réel avec instance('INSTANCE_NAME') . Si vous ne spécifiez pas d'instance, la fonction se déploie sur l'instance de base de données en temps réel par défaut pour le projet Firebase. Par exemple :

  • Instance de base de données en temps réel par défaut : functions.database.ref('/foo/bar')
  • Instance nommée "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')

Ces méthodes ordonnent à votre fonction de gérer les écritures sur un certain chemin dans l'instance de la base de données en temps réel. Les spécifications de chemin correspondent à toutes les écritures qui touchent un chemin, y compris les écritures qui se produisent n'importe où en dessous. Si vous définissez le chemin de votre fonction comme /foo/bar , il correspond aux événements à 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 les données d'événement incluent les anciennes et les nouvelles données à /foo/bar . Si les données d'événement peuvent être volumineuses, envisagez d'utiliser plusieurs fonctions sur des chemins plus profonds au lieu d'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.

Vous pouvez spécifier un composant de chemin comme caractère générique en l'entourant d'accolades ; ref('foo/{bar}') correspond à n'importe quel enfant de /foo . Les valeurs de ces composants de chemin génériques sont disponibles dans l'objet EventContext.params de votre fonction. Dans cet exemple, la valeur est disponible en tant que context.params.bar .

Les chemins avec des caractères génériques peuvent correspondre à plusieurs événements à partir d'une seule écriture. Un insert de

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

correspond au chemin "/foo/{bar}" deux fois : une fois avec "hello": "world" et une autre fois avec "firebase": "functions" .

Gérer les données d'événement

Lors de la gestion d'un événement Realtime Database, l'objet de données renvoyé est un DataSnapshot . Pour les événements onWrite ou onUpdate , le premier paramètre est un objet Change qui contient deux instantanés qui représentent l'état des données avant et après l'événement déclencheur. Pour les événements onCreate et onDelete , l'objet de données renvoyé est un instantané des données créées ou supprimées.

Dans cet exemple, la fonction récupère l'instantané pour le chemin spécifié en tant que snap , convertit la chaîne à cet emplacement en majuscules et écrit cette chaîne modifiée dans la base de données :

// 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);
    });

Accéder aux informations d'authentification de l'utilisateur

À partir de EventContext.auth et EventContext.authType , vous pouvez accéder aux informations utilisateur, y compris les autorisations, pour l'utilisateur qui a déclenché une fonction. Cela peut être utile pour appliquer des règles de sécurité, permettant à votre fonction d'effectuer différentes opérations en fonction du niveau d'autorisation de l'utilisateur :

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);
      }
    });

En outre, vous pouvez tirer parti des informations d'authentification de l'utilisateur pour "emprunter l'identité" d'un utilisateur et effectuer des opérations d'écriture au nom de l'utilisateur. Assurez-vous de supprimer l'instance d'application comme indiqué ci-dessous afin d'éviter les problèmes de simultanéité :

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));
      });
    });

Lecture de la valeur précédente

L'objet Change a une propriété before qui vous permet d'inspecter ce qui a été enregistré dans la base de données en temps réel avant l'événement. La propriété before renvoie un DataSnapshot où toutes les méthodes (par exemple, val() et exists() ) font référence à la valeur précédente. Vous pouvez relire la nouvelle valeur en utilisant le DataSnapshot d'origine ou en lisant la propriété after . Cette propriété sur tout Change est un autre DataSnapshot représentant l'état des données après que l'événement se soit produit.

Par exemple, la propriété before peut être utilisée pour s'assurer que la fonction ne met que du texte en majuscule lors de sa première création :

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);
    });