Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

ทริกเกอร์ฐานข้อมูลเรียลไทม์

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

Cloud Functions ช่วยให้คุณจัดการเหตุการณ์ในฐานข้อมูลเรียลไทม์ของ Firebase โดยไม่จำเป็นต้องอัปเดตโค้ดไคลเอ็นต์ Cloud Functions ช่วยให้คุณเรียกใช้การดำเนินการ Realtime Database ด้วยสิทธิ์การดูแลระบบเต็มรูปแบบ และทำให้แน่ใจว่าการเปลี่ยนแปลงแต่ละรายการใน Realtime Database จะได้รับการประมวลผลทีละรายการ คุณเปลี่ยนแปลงฐานข้อมูลเรียลไทม์ของ Firebase ได้ผ่าน DataSnapshot หรือผ่าน Admin SDK

ในวงจรชีวิตทั่วไป ฟังก์ชันฐานข้อมูลเรียลไทม์ของ Firebase จะทำสิ่งต่อไปนี้:

  1. รอการเปลี่ยนแปลงตำแหน่งฐานข้อมูลเรียลไทม์เฉพาะ
  2. ทริกเกอร์เมื่อเหตุการณ์เกิดขึ้นและดำเนินการ (ดู ฉันจะทำอะไรกับ Cloud Functions ได้บ้าง สำหรับตัวอย่างกรณีการใช้งาน)
  3. รับออบเจ็กต์ข้อมูลที่มีสแน็ปช็อตของข้อมูลที่จัดเก็บไว้ในเอกสารที่ระบุ

เรียกใช้ฟังก์ชันฐานข้อมูลเรียลไทม์

สร้างฟังก์ชันใหม่สำหรับเหตุการณ์ Realtime Database ด้วย functions.database ในการควบคุมเวลาที่ฟังก์ชันทริกเกอร์ ให้ระบุตัวจัดการเหตุการณ์ตัวใดตัวหนึ่ง และระบุพาธ Realtime Database ที่จะรับฟังเหตุการณ์

ตั้งค่าตัวจัดการเหตุการณ์

ฟังก์ชันช่วยให้คุณจัดการเหตุการณ์ Realtime Database ที่ระดับความจำเพาะสองระดับ คุณสามารถฟังเฉพาะเหตุการณ์ที่สร้าง อัปเดต หรือการลบเท่านั้น หรือคุณสามารถฟังการเปลี่ยนแปลงใดๆ ของเส้นทางก็ได้ Cloud Functions รองรับตัวจัดการเหตุการณ์เหล่านี้สำหรับ Realtime Database:

  • onWrite() ซึ่งจะทริกเกอร์เมื่อมีการสร้าง อัปเดต หรือลบข้อมูลในฐานข้อมูลเรียลไทม์
  • onCreate() ซึ่งจะทริกเกอร์เมื่อมีการสร้างข้อมูลใหม่ในฐานข้อมูลเรียลไทม์
  • onUpdate() ซึ่งจะทริกเกอร์เมื่อมีการอัปเดตข้อมูลใน Realtime Database
  • onDelete() ซึ่งจะทริกเกอร์เมื่อข้อมูลถูกลบออกจากฐานข้อมูลเรียลไทม์

ระบุอินสแตนซ์และเส้นทาง

ในการควบคุมเวลาและตำแหน่งที่ฟังก์ชันของคุณควรทริกเกอร์ ให้เรียก ref(path) เพื่อระบุพาธ และระบุอินสแตนซ์ฐานข้อมูลเรียลไทม์ด้วย instance('INSTANCE_NAME') หากคุณไม่ได้ระบุอินสแตนซ์ ฟังก์ชันจะปรับใช้กับอินสแตนซ์ฐานข้อมูลเรียลไทม์เริ่มต้นสำหรับโปรเจ็กต์ Firebase ตัวอย่างเช่น

  • อินสแตนซ์ฐานข้อมูลเรียลไทม์เริ่มต้น: functions.database.ref('/foo/bar')
  • อินสแตนซ์ชื่อ "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')

เมธอดเหล่านี้สั่งให้ฟังก์ชันของคุณจัดการกับการเขียนบนเส้นทางที่แน่นอนภายในอินสแตนซ์ฐานข้อมูลเรียลไทม์ ข้อมูลจำเพาะของเส้นทางตรงกับการเขียน ทั้งหมด ที่สัมผัสเส้นทาง รวมถึงการเขียนที่เกิดขึ้นที่ใดก็ได้ด้านล่าง หากคุณกำหนดเส้นทางสำหรับฟังก์ชันของคุณเป็น /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 ออบเจ็กต์ข้อมูลที่ส่งคืนคือสแน็ปช็อตของข้อมูลที่สร้างหรือลบ

ในตัวอย่างนี้ ฟังก์ชันดึงสแน็ปช็อตสำหรับพาธที่ระบุเป็น snap แปลงสตริงที่ตำแหน่งนั้นเป็นตัวพิมพ์ใหญ่ และเขียนสตริงที่แก้ไขนั้นไปยังฐานข้อมูล:

// 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 ที่ให้คุณตรวจสอบสิ่งที่บันทึกไว้ใน 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);
    });