Con Cloud Functions, puoi gestire eventi nel
Firebase Realtime Database senza bisogno di aggiornare il codice client.
Cloud Functions ti consente di eseguire operazioni Realtime Database con funzioni amministrative complete
privilegi e garantisce che ogni modifica a Realtime Database venga elaborata
singolarmente. Puoi apportare Firebase Realtime Database modifiche tramite
DataSnapshot
o tramite l'SDK Admin.
In un ciclo di vita tipico, una funzione Firebase Realtime Database svolge le seguenti operazioni:
- Attende le modifiche a una determinata sede di Realtime Database.
- Si attiva quando si verifica un evento ed esegue le sue attività (vedi Che cosa posso fare con Cloud Functions? per esempi di e casi d'uso specifici).
- Riceve un oggetto dati contenente uno snapshot dei dati archiviati nel documento specificato.
Attiva una funzione Realtime Database
Crea nuove funzioni per gli eventi Realtime Database con functions.database
. Per controllare quando viene attivata la funzione, specifica uno dei gestori di eventi e il percorso Realtime Database in cui verranno ascoltati gli eventi.
Imposta il gestore di eventi
Le funzioni ti consentono di gestire gli eventi Realtime Database a due livelli di specificità: puoi ascoltare specificamente solo gli eventi di creazione, aggiornamento o cancellazione oppure puoi ascoltare qualsiasi modifica di qualsiasi tipo a un percorso. Cloud Functions supporta questi gestori di eventi per Realtime Database:
onWrite()
, che si attiva quando i dati vengono creati, aggiornati o eliminati in Realtime Database.onCreate()
, che si attiva quando vengono creati nuovi dati in Realtime Database.onUpdate()
, che si attiva quando i dati vengono aggiornati in Realtime Database .onDelete()
, che si attiva quando i dati vengono eliminati da Realtime Database.
Specifica l'istanza e il percorso
Per controllare quando e dove deve essere attivata la funzione, chiama ref(path)
per specificare un percorso e, facoltativamente, specificare un'istanza Realtime Database
con instance('INSTANCE_NAME')
. Se non specifichi un'istanza, la funzione viene dispiattata nell'istanza Realtime Database predefinita per il progetto Firebase. Ad esempio:
- Istanza Realtime Database predefinita:
functions.database.ref('/foo/bar')
- Istanza denominata "my-app-db-2":
functions.database.instance('my-app-db-2').ref('/foo/bar')
Questi metodi indirizzano la funzione a gestire le scritture su un determinato percorso all'interno di
l'istanza Realtime Database. Le specifiche del percorso corrispondono a tutte le scritture che riguardano un percorso,
incluse le scritture
che si verificano in qualsiasi punto sottostante. Se imposti il percorso
per la tua funzione come /foo/bar
, viene trovata una corrispondenza con gli eventi in entrambe le seguenti posizioni:
/foo/bar
/foo/bar/baz/really/deep/path
In ogni caso, Firebase interpreta che l'evento si verifica alle ore /foo/bar
,
e i dati sugli eventi includono
i dati vecchi e nuovi di /foo/bar
. Se i dati sugli eventi
potrebbero essere di grandi dimensioni,
considera l'utilizzo di più funzioni con percorsi più profondi invece di una singola
in prossimità della radice del database. Per ottenere le migliori prestazioni, richiedi solo
i dati al livello più profondo possibile.
Puoi specificare un componente del percorso come carattere jolly circondandolo con
parentesi graffe; ref('foo/{bar}')
corrisponde a un qualsiasi elemento secondario di /foo
. I valori di questi componenti del percorso con caratteri jolly sono disponibili nell'oggetto EventContext.params
della funzione. In questo esempio, il valore è disponibile come
context.params.bar
.
I percorsi con caratteri jolly possono corrispondere a più eventi di una singola scrittura. Un inserto di
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
corrisponde al percorso "/foo/{bar}"
due volte: una volta con "hello": "world"
e di nuovo con "firebase": "functions"
.
Gestire i dati sugli eventi
Quando gestisci un evento Realtime Database, l'oggetto dati restituito è un
DataSnapshot
.
Per gli eventi onWrite
o onUpdate
, il valore
Il primo parametro è un oggetto Change
che contiene due snapshot
che rappresentano lo stato dei dati
e dopo l'evento di attivazione. Per gli eventi onCreate
e onDelete
:
l'oggetto dati restituito è un'istantanea dei dati creati o eliminati.
In questo esempio, la funzione recupera lo snapshot per il percorso specificato, converte la stringa in quella posizione in lettere maiuscole, e scrive la stringa modificata nel database:
// 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); });
Accesso alle informazioni di autenticazione utente
Da EventContext.auth
e EventContext.authType
,
puoi accedere
i dati dell'utente che ha attivato le modifiche, incluse le autorizzazioni
una funzione. Può essere utile per applicare regole di sicurezza,
consentendo alla tua funzione di completare diverse operazioni in base
livello di autorizzazione:
const functions = require('firebase-functions/v1');
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);
}
});
Inoltre, puoi utilizzare le informazioni di autenticazione dell'utente per "rubare l'identità" di un utente ed eseguire operazioni di scrittura per suo conto. Assicurati di eliminare dell'app, come mostrato di seguito, per evitare problemi di contemporaneità:
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));
});
});
Lettura del valore precedente
L'oggetto Change
ha una proprietà
before
che ti consente di ispezionare ciò che è stato salvato in Realtime Database prima dell'evento. La proprietà before
restituisce un DataSnapshot
in cui tutti i metodi (ad esempio val()
e exists()
) fanno riferimento al valore precedente. Puoi leggere di nuovo il nuovo valore utilizzando
DataSnapshot
originale o leggendo la proprietà
after
. Questa proprietà su qualsiasi Change
è un'altra proprietà DataSnapshot
che rappresenta
lo stato dei dati dopo che si è verificato l'evento.
Ad esempio, la proprietà before
può essere utilizzata per garantire che la funzione venga utilizzata solo
in maiuscolo al momento della creazione:
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);
});