Leggere e scrivere dati sul Web

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

(Facoltativo) Prototipazione e test con Firebase Local Emulator Suite

Prima di parlare di come la tua app legge e scrive in Realtime Database, introduciamo una serie di strumenti che puoi utilizzare per prototipare e testare la funzionalità di Realtime Database: Firebase Local Emulator Suite. Se stai provando diversi modelli di dati, ottimizzando le tue regole di sicurezza o lavorando per trovare il modo più conveniente per interagire con il back-end, essere in grado di lavorare localmente senza distribuire servizi live può essere un'ottima idea.

Un emulatore di database in tempo reale fa parte della Local Emulator Suite, che consente alla tua app di interagire con il contenuto e la configurazione del database emulato, nonché facoltativamente con le risorse del progetto emulato (funzioni, altri database e regole di sicurezza).

L'utilizzo dell'emulatore del database in tempo reale richiede solo pochi passaggi:

  1. Aggiunta di una riga di codice alla configurazione di test dell'app per connettersi all'emulatore.
  2. Dalla radice della directory del progetto locale, eseguendo firebase emulators:start .
  3. Effettuare chiamate dal codice prototipo della tua app utilizzando un SDK della piattaforma Realtime Database come di consueto o utilizzando l'API REST di Realtime Database.

È disponibile una procedura dettagliata che coinvolge Realtime Database e Cloud Functions . Dovresti anche dare un'occhiata all'introduzione di Local Emulator Suite .

Ottenere un riferimento al database

Per leggere o scrivere dati dal database, è necessaria un'istanza di firebase.database.Reference :

Web version 9

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web version 8

var database = firebase.database();

Scrivi dati

Questo documento illustra le nozioni di base sul recupero dei dati e su come ordinare e filtrare i dati di Firebase.

I dati di Firebase vengono recuperati collegando un listener asincrono a firebase.database.Reference . Il listener viene attivato una volta per lo stato iniziale dei dati e di nuovo ogni volta che i dati cambiano.

Operazioni di scrittura di base

Per le operazioni di scrittura di base, puoi utilizzare set() per salvare i dati in un riferimento specificato, sostituendo qualsiasi dato esistente in quel percorso. Ad esempio, un'applicazione di social blogging potrebbe aggiungere un utente con set() come segue:

Web version 9

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 version 8

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

L'utilizzo set() sovrascrive i dati nella posizione specificata, inclusi eventuali nodi figli.

Leggere i dati

Ascolta gli eventi di valore

Per leggere i dati in un percorso e ascoltare le modifiche, utilizzare onValue() per osservare gli eventi. È possibile utilizzare questo evento per leggere istantanee statiche dei contenuti in un determinato percorso, così come esistevano al momento dell'evento. Questo metodo viene attivato una volta quando il listener è collegato e di nuovo ogni volta che i dati, inclusi i figli, cambiano. Al callback dell'evento viene passato uno snapshot contenente tutti i dati in quella posizione, inclusi i dati figlio. Se non ci sono dati, l'istantanea restituirà false quando chiami exists() e null quando chiami val() su di essa.

L'esempio seguente mostra un'applicazione di social blogging che recupera il numero di stelle di un post dal database:

Web version 9

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 version 8

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

Il listener riceve uno snapshot che contiene i dati nella posizione specificata nel database al momento dell'evento. È possibile recuperare i dati nello snapshot con il metodo val() .

Leggere i dati una volta

Leggi i dati una volta con get()

L'SDK è progettato per gestire le interazioni con i server di database indipendentemente dal fatto che la tua app sia online o offline.

In genere, dovresti utilizzare le tecniche di evento valore descritte sopra per leggere i dati per ricevere notifiche degli aggiornamenti ai dati dal back-end. Le tecniche di ascolto riducono l'utilizzo e la fatturazione e sono ottimizzate per offrire ai tuoi utenti la migliore esperienza quando vanno online e offline.

Se hai bisogno dei dati solo una volta, puoi usare get() per ottenere un'istantanea dei dati dal database. Se per qualsiasi motivo get() non è in grado di restituire il valore del server, il client analizzerà la cache di archiviazione locale e restituirà un errore se il valore non viene ancora trovato.

L'uso non necessario di get() può aumentare l'uso della larghezza di banda e portare a una perdita di prestazioni, che può essere prevenuta utilizzando un ascoltatore in tempo reale come mostrato sopra.

Web version 9

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 version 8

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

Leggi i dati una volta con un osservatore

In alcuni casi potresti voler restituire immediatamente il valore dalla cache locale, invece di cercare un valore aggiornato sul server. In questi casi è possibile utilizzare once() per ottenere immediatamente i dati dalla cache del disco locale.

Questo è utile per i dati che devono essere caricati solo una volta e non è previsto che cambino frequentemente o richiedano un ascolto attivo. Ad esempio, l'app di blog negli esempi precedenti utilizza questo metodo per caricare il profilo di un utente quando inizia a creare un nuovo post:

Web version 9

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 version 8

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

Aggiornamento o cancellazione dei dati

Aggiorna campi specifici

Per scrivere simultaneamente su figli specifici di un nodo senza sovrascrivere altri nodi figli, utilizzare il metodo update() .

Quando si chiama update() , è possibile aggiornare i valori figlio di livello inferiore specificando un percorso per la chiave. Se i dati vengono archiviati in più posizioni per una migliore scalabilità, puoi aggiornare tutte le istanze di tali dati utilizzando il fan-out dei dati .

Ad esempio, un'app di social blogging potrebbe creare un post e aggiornarlo contemporaneamente al feed delle attività recenti e al feed delle attività dell'utente che ha pubblicato utilizzando un codice come questo:

Web version 9

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 version 8

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

Questo esempio utilizza push() per creare un post nel nodo contenente i post per tutti gli utenti in /posts/$postid e contemporaneamente recuperare la chiave. La chiave può quindi essere utilizzata per creare una seconda voce nei post dell'utente in /user-posts/$userid/$postid .

Utilizzando questi percorsi, puoi eseguire aggiornamenti simultanei in più posizioni nell'albero JSON con una singola chiamata a update() , ad esempio come questo esempio crea il nuovo post in entrambe le posizioni. Gli aggiornamenti simultanei effettuati in questo modo sono atomici: o tutti gli aggiornamenti riescono o tutti gli aggiornamenti falliscono.

Aggiungi una richiamata di completamento

Se vuoi sapere quando i tuoi dati sono stati impegnati, puoi aggiungere una richiamata di completamento. Sia set() che update() accettano un callback di completamento facoltativo che viene chiamato quando la scrittura è stata salvata nel database. Se la chiamata non ha avuto successo, al callback viene passato un oggetto errore che indica il motivo per cui si è verificato l'errore.

Web version 9

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 version 8

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

Elimina dati

Il modo più semplice per eliminare i dati è chiamare remove() su un riferimento alla posizione di quei dati.

Puoi anche eliminare specificando null come valore per un'altra operazione di scrittura come set() o update() . Puoi utilizzare questa tecnica con update() per eliminare più figli in una singola chiamata API.

Ricevi una Promise

Per sapere quando i tuoi dati vengono inviati al server Firebase Realtime Database, puoi utilizzare un Promise . Sia set() che update() possono restituire una Promise che puoi usare per sapere quando la scrittura è impegnata nel database.

Distacca gli ascoltatori

I callback vengono rimossi chiamando il metodo off() sul riferimento al database Firebase.

Puoi rimuovere un singolo listener passandolo come parametro a off() . Chiamare off() sulla posizione senza argomenti rimuove tutti i listener in quella posizione.

Chiamare off() su un listener genitore non rimuove automaticamente i listener registrati sui suoi nodi figli; off() deve essere chiamato anche su qualsiasi listener figlio per rimuovere la richiamata.

Salva i dati come transazioni

Quando si lavora con dati che potrebbero essere danneggiati da modifiche simultanee, come i contatori incrementali, è possibile utilizzare un'operazione di transazione . È possibile assegnare a questa operazione una funzione di aggiornamento e un callback di completamento facoltativo. La funzione di aggiornamento accetta lo stato corrente dei dati come argomento e restituisce il nuovo stato desiderato che si desidera scrivere. Se un altro client scrive nella posizione prima che il nuovo valore sia stato scritto correttamente, la funzione di aggiornamento viene chiamata di nuovo con il nuovo valore corrente e la scrittura viene ritentata.

Ad esempio, nell'app di social blogging di esempio, puoi consentire agli utenti di contrassegnare e rimuovere i post da Speciali e tenere traccia di quante stelle ha ricevuto un post come segue:

Web version 9

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 version 8

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'utilizzo di una transazione impedisce che i conteggi delle stelle siano errati se più utenti segnalano lo stesso post contemporaneamente o se il cliente disponeva di dati obsoleti. Se la transazione viene rifiutata, il server restituisce il valore corrente al client, che esegue nuovamente la transazione con il valore aggiornato. Questo si ripete fino a quando la transazione non viene accettata o si interrompe la transazione.

Incrementi atomici lato server

Nel caso d'uso sopra, stiamo scrivendo due valori nel database: l'ID dell'utente che contrassegna/annulla il post e il numero di stelle incrementato. Se sappiamo già che l'utente sta recitando il post, possiamo usare un'operazione di incremento atomico invece di una transazione.

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

Questo codice non usa un'operazione di transazione, quindi non viene rieseguito automaticamente in caso di aggiornamento in conflitto. Tuttavia, poiché l'operazione di incremento avviene direttamente sul server del database, non vi è alcuna possibilità di conflitto.

Se desideri rilevare e rifiutare i conflitti specifici dell'applicazione, ad esempio un utente che recita un post che ha già aggiunto a Speciali in precedenza, dovresti scrivere regole di sicurezza personalizzate per quel caso d'uso.

Lavora con i dati offline

Se un client perde la connessione di rete, la tua app continuerà a funzionare correttamente.

Ogni client connesso a un database Firebase mantiene la propria versione interna di tutti i dati attivi. Quando i dati vengono scritti, vengono prima scritti in questa versione locale. Il client Firebase sincronizza quindi tali dati con i server di database remoti e con altri client in base al "massimo sforzo".

Di conseguenza, tutte le scritture nel database attivano immediatamente gli eventi locali, prima che i dati vengano scritti nel server. Ciò significa che la tua app rimane reattiva indipendentemente dalla latenza di rete o dalla connettività.

Una volta ristabilita la connettività, la tua app riceve il set di eventi appropriato in modo che il client si sincronizzi con lo stato del server corrente, senza dover scrivere alcun codice personalizzato.

Parleremo di più sul comportamento offline in Ulteriori informazioni sulle funzionalità online e offline ..

Prossimi passi

,

(Facoltativo) Prototipazione e test con Firebase Local Emulator Suite

Prima di parlare di come la tua app legge e scrive in Realtime Database, introduciamo una serie di strumenti che puoi utilizzare per prototipare e testare la funzionalità di Realtime Database: Firebase Local Emulator Suite. Se stai provando diversi modelli di dati, ottimizzando le tue regole di sicurezza o lavorando per trovare il modo più conveniente per interagire con il back-end, essere in grado di lavorare localmente senza distribuire servizi live può essere un'ottima idea.

Un emulatore di database in tempo reale fa parte della Local Emulator Suite, che consente alla tua app di interagire con il contenuto e la configurazione del database emulato, nonché facoltativamente con le risorse del progetto emulato (funzioni, altri database e regole di sicurezza).

L'utilizzo dell'emulatore del database in tempo reale richiede solo pochi passaggi:

  1. Aggiunta di una riga di codice alla configurazione di test dell'app per connettersi all'emulatore.
  2. Dalla radice della directory del progetto locale, eseguendo firebase emulators:start .
  3. Effettuare chiamate dal codice prototipo della tua app utilizzando un SDK della piattaforma Realtime Database come di consueto o utilizzando l'API REST di Realtime Database.

È disponibile una procedura dettagliata che coinvolge Realtime Database e Cloud Functions . Dovresti anche dare un'occhiata all'introduzione di Local Emulator Suite .

Ottenere un riferimento al database

Per leggere o scrivere dati dal database, è necessaria un'istanza di firebase.database.Reference :

Web version 9

import { getDatabase } from "firebase/database";

const database = getDatabase();

Web version 8

var database = firebase.database();

Scrivi dati

Questo documento illustra le nozioni di base sul recupero dei dati e su come ordinare e filtrare i dati di Firebase.

I dati di Firebase vengono recuperati collegando un listener asincrono a firebase.database.Reference . Il listener viene attivato una volta per lo stato iniziale dei dati e di nuovo ogni volta che i dati cambiano.

Operazioni di scrittura di base

Per le operazioni di scrittura di base, puoi utilizzare set() per salvare i dati in un riferimento specificato, sostituendo qualsiasi dato esistente in quel percorso. Ad esempio, un'applicazione di social blogging potrebbe aggiungere un utente con set() come segue:

Web version 9

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 version 8

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

L'utilizzo set() sovrascrive i dati nella posizione specificata, inclusi eventuali nodi figli.

Leggere i dati

Ascolta gli eventi di valore

Per leggere i dati in un percorso e ascoltare le modifiche, utilizzare onValue() per osservare gli eventi. È possibile utilizzare questo evento per leggere istantanee statiche dei contenuti in un determinato percorso, così come esistevano al momento dell'evento. Questo metodo viene attivato una volta quando il listener è collegato e di nuovo ogni volta che i dati, inclusi i figli, cambiano. Al callback dell'evento viene passato uno snapshot contenente tutti i dati in quella posizione, inclusi i dati figlio. Se non ci sono dati, l'istantanea restituirà false quando chiami exists() e null quando chiami val() su di essa.

L'esempio seguente mostra un'applicazione di social blogging che recupera il numero di stelle di un post dal database:

Web version 9

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 version 8

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

Il listener riceve uno snapshot che contiene i dati nella posizione specificata nel database al momento dell'evento. È possibile recuperare i dati nello snapshot con il metodo val() .

Leggere i dati una volta

Leggi i dati una volta con get()

L'SDK è progettato per gestire le interazioni con i server di database indipendentemente dal fatto che la tua app sia online o offline.

In genere, dovresti utilizzare le tecniche di evento valore descritte sopra per leggere i dati per ricevere notifiche degli aggiornamenti ai dati dal back-end. Le tecniche di ascolto riducono l'utilizzo e la fatturazione e sono ottimizzate per offrire ai tuoi utenti la migliore esperienza quando vanno online e offline.

Se hai bisogno dei dati solo una volta, puoi usare get() per ottenere un'istantanea dei dati dal database. Se per qualsiasi motivo get() non è in grado di restituire il valore del server, il client analizzerà la cache di archiviazione locale e restituirà un errore se il valore non viene ancora trovato.

L'uso non necessario di get() può aumentare l'uso della larghezza di banda e portare a una perdita di prestazioni, che può essere prevenuta utilizzando un ascoltatore in tempo reale come mostrato sopra.

Web version 9

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 version 8

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

Leggi i dati una volta con un osservatore

In alcuni casi potresti voler restituire immediatamente il valore dalla cache locale, invece di cercare un valore aggiornato sul server. In questi casi è possibile utilizzare once() per ottenere immediatamente i dati dalla cache del disco locale.

Questo è utile per i dati che devono essere caricati solo una volta e non è previsto che cambino frequentemente o richiedano un ascolto attivo. Ad esempio, l'app di blog negli esempi precedenti utilizza questo metodo per caricare il profilo di un utente quando inizia a creare un nuovo post:

Web version 9

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 version 8

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

Aggiornamento o cancellazione dei dati

Aggiorna campi specifici

Per scrivere simultaneamente su figli specifici di un nodo senza sovrascrivere altri nodi figli, utilizzare il metodo update() .

Quando si chiama update() , è possibile aggiornare i valori figlio di livello inferiore specificando un percorso per la chiave. Se i dati vengono archiviati in più posizioni per una migliore scalabilità, puoi aggiornare tutte le istanze di tali dati utilizzando il fan-out dei dati .

Ad esempio, un'app di social blogging potrebbe creare un post e aggiornarlo contemporaneamente al feed delle attività recenti e al feed delle attività dell'utente che ha pubblicato utilizzando un codice come questo:

Web version 9

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 version 8

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

Questo esempio utilizza push() per creare un post nel nodo contenente i post per tutti gli utenti in /posts/$postid e contemporaneamente recuperare la chiave. La chiave può quindi essere utilizzata per creare una seconda voce nei post dell'utente in /user-posts/$userid/$postid .

Utilizzando questi percorsi, puoi eseguire aggiornamenti simultanei in più posizioni nell'albero JSON con una singola chiamata a update() , ad esempio come questo esempio crea il nuovo post in entrambe le posizioni. Gli aggiornamenti simultanei effettuati in questo modo sono atomici: o tutti gli aggiornamenti riescono o tutti gli aggiornamenti falliscono.

Aggiungi una richiamata di completamento

Se vuoi sapere quando i tuoi dati sono stati impegnati, puoi aggiungere una richiamata di completamento. Sia set() che update() accettano un callback di completamento facoltativo che viene chiamato quando la scrittura è stata salvata nel database. Se la chiamata non ha avuto successo, al callback viene passato un oggetto errore che indica il motivo per cui si è verificato l'errore.

Web version 9

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 version 8

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

Elimina dati

Il modo più semplice per eliminare i dati è chiamare remove() su un riferimento alla posizione di quei dati.

Puoi anche eliminare specificando null come valore per un'altra operazione di scrittura come set() o update() . Puoi utilizzare questa tecnica con update() per eliminare più figli in una singola chiamata API.

Ricevi una Promise

Per sapere quando i tuoi dati vengono inviati al server Firebase Realtime Database, puoi utilizzare un Promise . Sia set() che update() possono restituire una Promise che puoi usare per sapere quando la scrittura è impegnata nel database.

Distacca gli ascoltatori

I callback vengono rimossi chiamando il metodo off() sul riferimento al database Firebase.

Puoi rimuovere un singolo listener passandolo come parametro a off() . Chiamare off() sulla posizione senza argomenti rimuove tutti i listener in quella posizione.

Chiamare off() su un listener genitore non rimuove automaticamente i listener registrati sui suoi nodi figli; off() deve essere chiamato anche su qualsiasi listener figlio per rimuovere la richiamata.

Salva i dati come transazioni

Quando si lavora con dati che potrebbero essere danneggiati da modifiche simultanee, come i contatori incrementali, è possibile utilizzare un'operazione di transazione . È possibile assegnare a questa operazione una funzione di aggiornamento e un callback di completamento facoltativo. La funzione di aggiornamento accetta lo stato corrente dei dati come argomento e restituisce il nuovo stato desiderato che si desidera scrivere. Se un altro client scrive nella posizione prima che il nuovo valore sia stato scritto correttamente, la funzione di aggiornamento viene chiamata di nuovo con il nuovo valore corrente e la scrittura viene ritentata.

Ad esempio, nell'app di social blogging di esempio, puoi consentire agli utenti di contrassegnare e rimuovere i post da Speciali e tenere traccia di quante stelle ha ricevuto un post come segue:

Web version 9

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 version 8

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'utilizzo di una transazione impedisce che i conteggi delle stelle siano errati se più utenti segnalano lo stesso post contemporaneamente o se il cliente disponeva di dati obsoleti. Se la transazione viene rifiutata, il server restituisce il valore corrente al client, che esegue nuovamente la transazione con il valore aggiornato. Questo si ripete fino a quando la transazione non viene accettata o si interrompe la transazione.

Incrementi atomici lato server

Nel caso d'uso sopra, stiamo scrivendo due valori nel database: l'ID dell'utente che contrassegna/annulla il post e il numero di stelle incrementato. Se sappiamo già che l'utente sta recitando il post, possiamo usare un'operazione di incremento atomico invece di una transazione.

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

Questo codice non usa un'operazione di transazione, quindi non viene rieseguito automaticamente in caso di aggiornamento in conflitto. Tuttavia, poiché l'operazione di incremento avviene direttamente sul server del database, non vi è alcuna possibilità di conflitto.

Se desideri rilevare e rifiutare i conflitti specifici dell'applicazione, ad esempio un utente che recita un post che ha già aggiunto a Speciali in precedenza, dovresti scrivere regole di sicurezza personalizzate per quel caso d'uso.

Lavora con i dati offline

Se un client perde la connessione di rete, la tua app continuerà a funzionare correttamente.

Ogni client connesso a un database Firebase mantiene la propria versione interna di tutti i dati attivi. Quando i dati vengono scritti, vengono prima scritti in questa versione locale. Il client Firebase sincronizza quindi tali dati con i server di database remoti e con altri client in base al "massimo sforzo".

Di conseguenza, tutte le scritture nel database attivano immediatamente gli eventi locali, prima che i dati vengano scritti nel server. Ciò significa che la tua app rimane reattiva indipendentemente dalla latenza di rete o dalla connettività.

Una volta ristabilita la connettività, la tua app riceve il set di eventi appropriato in modo che il client si sincronizzi con lo stato del server corrente, senza dover scrivere alcun codice personalizzato.

Parleremo di più sul comportamento offline in Ulteriori informazioni sulle funzionalità online e offline ..

Prossimi passi