Lire et écrire des données sur le Web

(Facultatif) Prototyper et tester avec Firebase Local Emulator Suite

Avant d'aborder la façon dont votre application lit et écrit dans Realtime Database, Découvrons un ensemble d'outils que vous pouvez utiliser pour prototyper et tester Realtime Database fonctionnalité: Firebase Local Emulator Suite. Si vous testez différentes données en optimisant vos règles de sécurité, ou en tentant d'identifier moyen rentable d'interagir avec le backend, en étant capable de travailler localement sans déployer de services en temps réel peut être une excellente idée.

Un émulateur Realtime Database fait partie de Local Emulator Suite, qui permet à votre application d'interagir avec le contenu et la configuration de votre base de données émulée, et éventuellement les ressources de projet émulées (fonctions, autres bases de données, et règles de sécurité).

L'utilisation de l'émulateur Realtime Database ne nécessite que quelques étapes:

  1. Ajoutez une ligne de code à la configuration de test de votre application pour vous connecter à l'émulateur.
  2. À partir de la racine du répertoire local de votre projet, exécutez firebase emulators:start.
  3. Effectuer des appels à partir du code du prototype de votre application à l'aide d'une plate-forme Realtime Database SDK comme d'habitude, ou à l'aide de l'API REST Realtime Database.

Un tutoriel détaillé impliquant Realtime Database et Cloud Functions est disponible. Vous pouvez également consulter l'introduction de Local Emulator Suite.

Obtenir une référence de base de données

Pour lire ou écrire des données depuis la base de données, vous avez besoin d'une instance de firebase.database.Reference:

Web

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web

var database = firebase.database();

Écrire des données

Ce document couvre les bases de la récupération des données et comment organiser et filtrer Données Firebase.

Les données Firebase sont récupérées en attachant un écouteur asynchrone à un firebase.database.Reference L'écouteur est déclenché une fois l'état initial des données et chaque fois qu'elles changent.

Opérations d'écriture de base

Pour les opérations d'écriture de base, vous pouvez utiliser set() pour enregistrer des données dans un en remplaçant toutes les données existantes de ce chemin. Par exemple, de blog peut ajouter un utilisateur avec set() comme suit:

Web

import { getDatabase, ref, set } from "firebase/database";

function writeUserData(userId, name, email, imageUrl) {
  const db = getDatabase();
  set(ref(db, 'users/' + userId), {
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

Web

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

L'utilisation de set() écrase les données à l'emplacement spécifié, y compris les enfants nœuds.

Lire des données

Écouter les événements de valeur

Pour lire des données sur un chemin d'accès et écouter les modifications, utilisez onValue() pour observer événements. Vous pouvez utiliser cet événement pour lire des instantanés statiques du contenu à un un chemin d'accès donné, car ils existaient au moment de l'événement. Cette méthode se déclenche une fois lorsque l'écouteur est associé et à nouveau chaque fois que les données, y compris les enfants, changent. Le rappel d'événement reçoit un instantané contenant toutes les données à cet emplacement, y compris les données de l'enfant. En l'absence de données, l'instantané renvoie false lorsque vous appelez exists() et null lorsque vous appelez val() dessus.

L'exemple suivant illustre une application de blog sur les réseaux sociaux qui récupère les Nombre d'étoiles d'un article de la base de données:

Web

import { getDatabase, ref, onValue } from "firebase/database";

const db = getDatabase();
const starCountRef = ref(db, 'posts/' + postId + '/starCount');
onValue(starCountRef, (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

Web

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', (snapshot) => {
  const data = snapshot.val();
  updateStarCount(postElement, data);
});

L'écouteur reçoit un snapshot contenant les données au niveau emplacement dans la base de données au moment de l'événement. Vous pouvez récupérer les données dans snapshot avec la méthode val().

Lire les données une fois

Lire les données une seule fois avec get()

Le SDK est conçu pour gérer les interactions avec les serveurs de base de données, que votre l'application est en ligne ou hors connexion.

En règle générale, vous devez utiliser les techniques d'événement de valeur décrites ci-dessus pour lire pour être averti des mises à jour des données du backend. Les techniques d'écouteur réduisent votre utilisation et votre facturation, et sont optimisées pour offrir à vos utilisateurs la meilleure expérience lorsqu'ils se connectent et se déconnectent.

Si vous n'avez besoin des données qu'une seule fois, vous pouvez utiliser get() pour obtenir un instantané de de la base de données. Si, pour une raison quelconque, get() ne parvient pas à renvoyer la valeur du serveur, le client sonde le cache de stockage local et renvoie une erreur si la valeur n'est toujours pas trouvée.

Une utilisation inutile de get() peut augmenter l'utilisation de la bande passante et entraîner une perte de qui peuvent être évitées en utilisant un écouteur en temps réel, comme indiqué ci-dessus.

Web

import { getDatabase, ref, child, get } from "firebase/database";

const dbRef = ref(getDatabase());
get(child(dbRef, `users/${userId}`)).then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Web

const dbRef = firebase.database().ref();
dbRef.child("users").child(userId).get().then((snapshot) => {
  if (snapshot.exists()) {
    console.log(snapshot.val());
  } else {
    console.log("No data available");
  }
}).catch((error) => {
  console.error(error);
});

Lire les données une fois avec un observateur

Dans certains cas, vous pouvez souhaiter que la valeur du cache local soit renvoyée immédiatement, au lieu de rechercher une valeur mise à jour sur le serveur. Dans ces vous pouvez utiliser once() pour récupérer immédiatement les données du cache du disque local.

Cela est utile pour les données qui ne doivent être chargées qu'une seule fois et qui ne devraient pas changer fréquemment ni nécessiter une écoute active. Par exemple, l'application de blog utilise cette méthode pour charger le profil d'un utilisateur commencez à rédiger un nouveau message:

Web

import { getDatabase, ref, onValue } from "firebase/database";
import { getAuth } from "firebase/auth";

const db = getDatabase();
const auth = getAuth();

const userId = auth.currentUser.uid;
return onValue(ref(db, '/users/' + userId), (snapshot) => {
  const username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
}, {
  onlyOnce: true
});

Web

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then((snapshot) => {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

Mettre à jour ou supprimer des données

Mettre à jour des champs spécifiques

Pour écrire simultanément sur des enfants spécifiques d'un nœud sans écraser d'autres les nœuds enfants, utilisez la méthode update().

Lorsque vous appelez update(), vous pouvez mettre à jour les valeurs enfants de niveau inférieur en spécifiant un chemin d'accès pour la clé. Si les données sont stockées dans plusieurs emplacements vous pouvez mettre à jour toutes les instances de ces données distribution ramifiée des données.

Par exemple, une application de blog sur les réseaux sociaux peut créer un article et mettre à jour simultanément au flux d'activité récente et au flux d'activité de l'utilisateur ayant publié la publication en utilisant comme ceci:

Web

import { getDatabase, ref, child, push, update } from "firebase/database";

function writeNewPost(uid, username, picture, title, body) {
  const db = getDatabase();

  // A post entry.
  const postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  const newPostKey = push(child(ref(db), 'posts')).key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  const updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return update(ref(db), updates);
}

Web

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

Cet exemple utilise push() pour créer un post dans le nœud contenant des posts pour tous les utilisateurs de /posts/$postid et récupèrent simultanément la clé. La clé peut ensuite être utilisée pour créer une deuxième entrée dans les posts de l'utilisateur à l'emplacement /user-posts/$userid/$postid.

Ces chemins d'accès vous permettent d'effectuer des mises à jour simultanées de plusieurs emplacements dans l'arborescence JSON avec un seul appel à update(), comme dans cet exemple crée le post aux deux emplacements. Mises à jour simultanées effectuées de cette manière sont atomiques: toutes les mises à jour réussissent ou échouent.

Ajouter un rappel de fin de session

Si vous souhaitez savoir quand vos données ont été validées, vous pouvez ajouter un rappel de fin. Saisie semi-automatique facultative pour set() et update() rappel appelé lorsque l'écriture a été validée dans la base de données. Si l'appel échoue, un objet d'erreur indiquant pourquoi l'échec s'est produit est transmis au rappel.

Web

import { getDatabase, ref, set } from "firebase/database";

const db = getDatabase();
set(ref(db, 'users/' + userId), {
  username: name,
  email: email,
  profile_picture : imageUrl
})
.then(() => {
  // Data saved successfully!
})
.catch((error) => {
  // The write failed...
});

Web

firebase.database().ref('users/' + userId).set({
  username: name,
  email: email,
  profile_picture : imageUrl
}, (error) => {
  if (error) {
    // The write failed...
  } else {
    // Data saved successfully!
  }
});

Supprimer des données

Le moyen le plus simple de supprimer des données consiste à appeler remove() sur une référence à l'emplacement de ces données.

Vous pouvez également supprimer en spécifiant null comme valeur pour une autre opération d'écriture, telle que set() ou update(). Vous pouvez utiliser cette technique avec update() pour supprimer plusieurs enfants dans un seul appel d'API.

Recevez un Promise

Pour savoir quand vos données sont validées sur le serveur Firebase Realtime Database, vous peut utiliser un Promise set() et update() peuvent tous deux renvoyer un Promise que vous pouvez utiliser pour savoir quand le l'écriture est validée dans la base de données.

Dissocier les écouteurs

Les rappels sont supprimés en appelant la méthode off() sur votre Documentation de référence sur la base de données Firebase

Vous pouvez supprimer un seul écouteur en le transmettant en tant que paramètre à off(). Appeler off() sur l'emplacement sans argument supprime tous les écouteurs à cet emplacement l'emplacement.

L'appel de off() sur un écouteur parent n'entraîne pas supprimer automatiquement les écouteurs enregistrés sur ses nœuds enfants ; off() doit également être appelé sur tous les écouteurs enfants. pour supprimer le rappel.

Enregistrer les données en tant que transactions

lorsque vous travaillez avec des données susceptibles d'être corrompues par des modifications, telles que des compteurs incrémentiels, vous pouvez utiliser un opération de transaction. Vous pouvez attribuer à cette opération une fonction de mise à jour et un rappel de fin facultatif. La fonction de mise à jour prend l'état actuel des données un argument et renvoie le nouvel état souhaité que vous souhaitez écrire. Si un autre client écrit à l'emplacement avant que la nouvelle valeur ne soit écrite, votre fonction de mise à jour est rappelée avec la nouvelle valeur actuelle ; et l'écriture est retentée.

Dans l'exemple d'application de blog sur les réseaux sociaux, vous pourriez autoriser les utilisateurs activer ou désactiver le suivi de posts et suivre le nombre d'étoiles qu'ils ont reçues ; comme suit:

Web

import { getDatabase, ref, runTransaction } from "firebase/database";

function toggleStar(uid) {
  const db = getDatabase();
  const postRef = ref(db, '/posts/foo-bar-123');

  runTransaction(postRef, (post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

Web

function toggleStar(postRef, uid) {
  postRef.transaction((post) => {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

L'utilisation d'une transaction permet d'éviter que le nombre d'étoiles soit incorrect si plusieurs les utilisateurs ont ajouté le même message à leurs favoris en même temps ou le client avait des données obsolètes. Si le transaction est rejetée, le serveur renvoie la valeur actuelle au client, qui exécute à nouveau la transaction avec le paramètre la valeur mise à jour. Cette opération se répète jusqu'à ce que la transaction soit acceptée ou que vous annuliez la transaction.

Incréments atomiques côté serveur

Dans le cas d'utilisation ci-dessus, nous écrivons deux valeurs dans la base de données: l'identifiant l'utilisateur qui a activé ou désactivé le suivi du post, ainsi que le nombre d'étoiles incrémenté. Si nous savez déjà que l'utilisateur ajoute le post aux favoris, nous pouvons utiliser un incrément atomique au lieu d'une transaction.

Web

function addStar(uid, key) {
  import { getDatabase, increment, ref, update } from "firebase/database";
  const dbRef = ref(getDatabase());

  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = increment(1);
  update(dbRef, updates);
}

Web

function addStar(uid, key) {
  const updates = {};
  updates[`posts/${key}/stars/${uid}`] = true;
  updates[`posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  updates[`user-posts/${key}/stars/${uid}`] = true;
  updates[`user-posts/${key}/starCount`] = firebase.database.ServerValue.increment(1);
  firebase.database().ref().update(updates);
}

Ce code n'utilise pas d'opération de transaction. Par conséquent, il n'obtient pas automatiquement réexécuté en cas de mise à jour incompatible. Toutefois, étant donné que l'opération d'incrémentation se produit directement sur le serveur de base de données, il n'y a aucun risque de conflit.

Si vous souhaitez détecter et rejeter les conflits propres à une application, tels qu'un conflit activer le suivi d'un post qu'il a déjà suivi, vous devez écrire des règles de sécurité pour ce cas d'utilisation.

Utiliser les données hors connexion

Si un client perd sa connexion réseau, votre application continuera de fonctionner correctement.

Chaque client connecté à une base de données Firebase gère sa propre version interne de toutes les données actives. Lorsque les données sont écrites, elles sont écrites dans cette version locale en premier. Le client Firebase synchronise ensuite ces données avec les serveurs de base de données distants et avec d'autres clients dans la mesure du possible.

Par conséquent, toutes les écritures dans la base de données déclenchent immédiatement des événements locaux, avant toutes les données sont écrites sur le serveur. Cela signifie que votre application quelle que soit la latence ou la connectivité du réseau.

Une fois la connectivité rétablie, votre application reçoit l'ensemble approprié de afin que le client se synchronise avec l'état actuel du serveur, sans avoir à et écrire n'importe quel code personnalisé.

Nous reviendrons sur le comportement hors connexion dans la section En savoir plus sur les fonctionnalités en ligne et hors connexion.

Étapes suivantes