הפעלת מסד נתונים בזמן אמת


עם פונקציות ענן, אתה יכול לטפל באירועים במסד הנתונים בזמן אמת של Firebase ללא צורך בעדכון קוד הלקוח. Cloud Functions מאפשרת לך להפעיל פעולות של מסד נתונים בזמן אמת עם הרשאות ניהול מלאות, ומבטיחה שכל שינוי במסד הנתונים של זמן אמת יעובד בנפרד. אתה יכול לבצע שינויים במסד הנתונים של Firebase בזמן אמת באמצעות DataSnapshot או דרך Admin SDK .

במחזור חיים טיפוסי, פונקציית Firebase Realtime Database עושה את הפעולות הבאות:

  1. ממתין לשינויים במיקום מסוים של מסד נתונים בזמן אמת.
  2. מופעל כאשר אירוע מתרחש ומבצע את המשימות שלו (ראה מה אני יכול לעשות עם פונקציות ענן? לקבלת דוגמאות למקרי שימוש).
  3. מקבל אובייקט נתונים המכיל תמונת מצב של הנתונים המאוחסנים במסמך שצוין.

הפעל פונקציית מסד נתונים בזמן אמת

צור פונקציות חדשות לאירועי מסד נתונים בזמן אמת עם functions.database . כדי לשלוט מתי הפונקציה מופעלת, ציין את אחד ממטפלי האירועים וציין את הנתיב של מסד הנתונים בזמן אמת שבו הוא יקשיב לאירועים.

הגדר את המטפל באירועים

פונקציות מאפשרות לך לטפל באירועי מסד נתונים בזמן אמת בשתי רמות ספציפיות; אתה יכול להאזין במיוחד לאירועי יצירה, עדכון או מחיקה בלבד, או שאתה יכול להאזין לכל שינוי מכל סוג בנתיב. Cloud Functions תומכת במטפלי אירועים אלה עבור מסד נתונים בזמן אמת:

  • onWrite() , המופעל כאשר נתונים נוצרים, מתעדכנים או נמחקים במסד נתונים בזמן אמת.
  • onCreate() , המופעל כאשר נתונים חדשים נוצרים במסד נתונים בזמן אמת.
  • onUpdate() , המופעל כאשר נתונים מתעדכנים במסד נתונים בזמן אמת.
  • onDelete() , המופעל כאשר נתונים נמחקים ממסד הנתונים בזמן אמת.

ציין את המופע והנתיב

כדי לשלוט מתי והיכן הפונקציה שלך אמורה להפעיל, קרא ref(path) כדי לציין נתיב, ואופציונלי ציין מופע של Realtime Database עם instance('INSTANCE_NAME') . אם לא תציין מופע, הפונקציה תפרוס למופע ברירת המחדל של Realtime Database עבור פרויקט Firebase. לדוגמה:

  • מופע ברירת מחדל של מסד נתונים בזמן אמת: 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 , אובייקט הנתונים המוחזר הוא תמונת מצב של הנתונים שנוצרו או נמחקו.

בדוגמה זו, הפונקציה מאחזרת את תמונת המצב עבור הנתיב שצוין, ממירה את המחרוזת במיקום זה לאותיות רישיות וכותבת את המחרוזת ששונתה למסד הנתונים:

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

כמו כן, ניתן למנף מידע אימות משתמש כדי "להתחזות" למשתמש ולבצע פעולות כתיבה בשמו של המשתמש. הקפד למחוק את מופע האפליקציה כפי שמוצג להלן כדי למנוע בעיות במקביל:

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 שמאפשר לך לבדוק מה נשמר במסד הנתונים בזמן אמת לפני האירוע. המאפיין 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);
    });