עם Cloud Functions אפשר לטפל באירועים
Firebase Realtime Database ללא צורך לעדכן את קוד הלקוח.
Cloud Functions מאפשר לך להריץ פעולות Realtime Database עם ניהול מלא
ומבטיח שכל שינוי שמבצעים ב-Realtime Database מעובד
בנפרד. אפשר לבצע שינויים בFirebase Realtime Database דרך
DataSnapshot
או דרך Admin SDK.
במחזור חיים רגיל, הפונקציה Firebase Realtime Database מבצעת את הפעולות הבאות:
- הפונקציה ממתינה לשינויים במיקום Realtime Database מסוים.
- מופעל כשאירוע מתרחש ומבצע את המשימות שלו (מידע נוסף זמין בקטע מה אפשר לעשות? עם Cloud Functions? לדוגמה, תרחישים לדוגמה).
- מקבל אובייקט נתונים שמכיל תמונת מצב של הנתונים המאוחסנים במסמך שצוין.
הפעלת פונקציית Realtime Database
יצירת פונקציות חדשות לאירועי Realtime Database
עם functions.database
. כדי לקבוע מתי הפונקציה מופעלת, מציינים את אחד מהגורמים המטפלים באירועים ואת הנתיב Realtime Database שבו הוא יקשיב לאירועים.
הגדרת הגורם המטפל באירועים
פונקציות מאפשרות לטפל באירועי Realtime Database בשתי רמות ספציפיות. אפשר להאזין להם באופן ספציפי לצורך יצירה, עדכון, או אירועי מחיקה, או להאזין לכל שינוי מכל סוג בנתיב. ב-Cloud Functions יש תמיכה בגורמים המטפלים באירועים של Realtime Database:
onWrite()
, שמופעל כאשר נוצרים, מתעדכנים או נמחקים נתונים ב-Realtime Database.onCreate()
, שמופעל כשנוצרים נתונים חדשים ב-Realtime Database.onUpdate()
, שמופעל כשהנתונים מתעדכנים ב-Realtime Database .onDelete()
, שמופעל כאשר נתונים נמחקים מ-Realtime Database .
ציון המופע והנתיב
כדי לקבוע מתי ואיפה הפונקציה תופעל, צריך להפעיל את ref(path)
כדי לציין נתיב, ואם רוצים, לציין מכונה של Realtime Database באמצעות instance('INSTANCE_NAME')
. אם לא מציינים מכונה, הפונקציה תופעל במכונה Realtime Database שמוגדרת כברירת מחדל לפרויקט ב-Firebase. לדוגמה:
- מופע ברירת המחדל של Realtime Database:
functions.database.ref('/foo/bar')
- מכונה בשם 'my-app-db-2':
functions.database.instance('my-app-db-2').ref('/foo/bar')
השיטות האלה מפנות את הפונקציה לטיפול בכתיבה בנתיב מסוים בתוך
במכונה Realtime Database. הגדרות הנתיב תואמות לכל פעולות הכתיבה שמשפיעות על נתיב, כולל פעולות כתיבה שמתרחשות בכל מקום מתחתיו. אם מגדירים את הנתיב
בשביל הפונקציה /foo/bar
, הוא תואם לאירועים בשני המיקומים הבאים:
/foo/bar
/foo/bar/baz/really/deep/path
בכל מקרה, מערכת Firebase מפרשת שהאירוע מתרחש בשעה /foo/bar
,
ונתוני האירועים כוללים
את הנתונים הישנים והחדשים ב-/foo/bar
. אם נתוני האירועים עשויים להיות גדולים,
כדאי להשתמש במספר פונקציות בנתיבים עמוקים יותר במקום בנקודה אחת
ליד השורש של מסד הנתונים. כדי ליהנות מהביצועים הטובים ביותר, צריך לשלוח בקשה
ברמה עמוקה ככל האפשר.
אפשר לציין רכיב נתיב כתו כללי לחיפוש על ידי הוספת עיגול מסולסל
סוגריים; ref('foo/{bar}')
תואם לכל צאצא של /foo
. הערכים של רכיבי הנתיב עם תווים כלליים זמינים באובייקט EventContext.params
של הפונקציה. בדוגמה הזו, הערך זמין באופן הבא:
context.params.bar
נתיבים עם תווים כלליים לחיפוש יכולים להתאים למספר אירועים בכתיבה אחת. הוספה של
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
תואם לנתיב "/foo/{bar}"
פעמיים: פעם אחת עם "hello": "world"
ושוב עם "firebase": "functions"
.
טיפול בנתוני אירועים
בטיפול באירוע Realtime Database, אובייקט הנתונים המוחזר הוא
DataSnapshot
.
עבור אירועים של onWrite
או onUpdate
,
הפרמטר הראשון הוא אובייקט Change
שמכיל שתי תמונות מצב
שמייצגים את מצב הנתונים
ואחרי האירוע המפעיל. עבור אירועים מסוג onCreate
ו-onDelete
,
אובייקט הנתונים המוחזר הוא תמונת מצב של הנתונים שנוצרו או נמחקו.
בדוגמה הזו, הפונקציה מאחזרת את קובץ ה-snapshot של הנתיב שצוין, ממיר את המחרוזת במיקום הזה לאותיות רישיות, וכותבת את המחרוזת ששונתה למסד הנתונים:
// 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); });
גישה לפרטי אימות של משתמשים
מקור: EventContext.auth
וגם EventContext.authType
,
שיש לך גישה
פרטי המשתמש, כולל הרשאות, של המשתמש שהפעיל
פונקציה. זה יכול להיות שימושי לצורך אכיפה של כללי אבטחה,
שמאפשרות לפונקציה להשלים פעולות שונות בהתאם
רמת הרשאות:
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);
}
});
בנוסף, אפשר להשתמש במידע על אימות המשתמשים כדי "להתחזות" למשתמש ולבצע פעולות כתיבה בשם המשתמש. חשוב למחוק את מופע של אפליקציה כפי שמוצג בהמשך כדי למנוע בעיות בו-זמניות (concurrency):
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));
});
});
קריאת הערך הקודם
לאובייקט Change
יש
before
שמאפשר לבדוק את מה שנשמר ב-Realtime Database לפני
אירוע. המאפיין before
מחזיר DataSnapshot
שבו כל
(לדוגמה,
val()
וגם
exists()
)
להתייחס לערך הקודם. אפשר לקרוא את הערך החדש שוב באמצעות
את DataSnapshot
המקורי או לקרוא את
after
לנכס. הנכס הזה בכל Change
הוא DataSnapshot
אחר שמייצג
מצב הנתונים אחרי האירוע.
לדוגמה, אפשר להשתמש במאפיין before
כדי לוודא שהפונקציה בלבד
טקסט באותיות גדולות כשהוא נוצר לראשונה:
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);
});