Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Pemicu Database

Dengan Cloud Functions, Anda dapat menangani peristiwa di Firebase Realtime Database tanpa harus memperbarui kode klien. Cloud Functions dapat Anda gunakan untuk menjalankan operasi Realtime Database dengan hak istimewa administratif penuh, dan memastikan setiap perubahan pada Realtime Database diproses secara terpisah. Anda dapat membuat perubahan pada Firebase Realtime Database melalui DataSnapshot atau Admin SDK.

Dalam siklus proses umum, fungsi Firebase Realtime Database melakukan hal-hal berikut:

  1. Menunggu perubahan pada lokasi Realtime Database tertentu.
  2. Terpicu ketika suatu peristiwa terjadi dan menjalankan tugasnya (untuk mengetahui contoh kasus penggunaan, baca artikel Apa yang bisa dilakukan dengan Cloud Functions?).
  3. Menerima objek data yang berisi snapshot data yang disimpan dalam dokumen yang ditentukan.

Memicu fungsi Realtime Database

Membuat fungsi baru untuk peristiwa Realtime Database dengan functions.database. Untuk mengontrol kapan fungsi terpicu, tentukan salah satu pengendali peristiwa dan tentukan jalur Realtime Database tempat peristiwa akan diproses.

Menentukan pengendali peristiwa

Dengan Functions, Anda dapat menangani peristiwa Realtime Database di dua tingkat kekhususan; yaitu Anda dapat memproses peristiwa pembuatan, pembaruan, atau penghapusan secara khusus, atau Anda dapat memproses perubahan apa pun ke suatu jalur. Cloud Functions mendukung pengendali peristiwa ini untuk Realtime Database:

  • onWrite(), yang terpicu saat data dibuat, diperbarui, atau dihapus di Realtime Database.
  • onCreate(), yang terpicu saat data baru dibuat di Realtime Database.
  • onUpdate(), yang terpicu saat data diperbarui di Realtime Database.
  • onDelete(), yang terpicu saat data dihapus dari Realtime Database.

Menentukan instance dan jalur

Untuk mengontrol kapan dan di mana fungsi Anda harus terpicu, panggil ref(path) untuk menentukan jalur, dan secara opsional tentukan instance Realtime Database dengan instance('INSTANCE_NAME'). Jika Anda tidak menentukan instance, fungsi tersebut akan di-deploy ke instance Realtime Database default untuk project Firebase. Misalnya:

  • Instance Realtime Database default: functions.database.ref('/foo/bar')
  • Instance dengan nama "my-app-db-2": functions.database.instance('my-app-db-2').ref('/foo/bar')

Metode ini akan mengarahkan fungsi Anda untuk menangani penulisan di jalur tertentu dalam instance Realtime Database. Spesifikasi jalur mencocokkan semua penulisan yang ada di jalur tertentu, termasuk penulisan yang terjadi di bawahnya. Jika Anda menetapkan /foo/bar sebagai jalur fungsi, peristiwa di kedua jalur ini akan dicocokkan:

 /foo/bar
 /foo/bar/baz/really/deep/path

Bagaimanapun juga, Firebase akan menafsirkan bahwa peristiwa terjadi di /foo/bar, dan data peristiwa menyertakan data lama dan baru di /foo/bar. Jika data peristiwa kemungkinan berukuran besar, pertimbangkan untuk menggunakan beberapa fungsi di jalur yang lebih dalam, bukan fungsi tunggal di dekat root database Anda. Untuk mendapatkan performa terbaik, hanya minta data di level sedalam mungkin.

Anda dapat menentukan komponen jalur sebagai karakter pengganti dengan mengurungnya menggunakan tanda kurung kurawal; ref('foo/{bar}') mencocokkan turunan apa pun dari /foo. Nilai komponen jalur karakter pengganti ini tersedia dalam objek EventContext.params di fungsi Anda. Dalam contoh ini, nilainya tersedia sebagai context.params.bar.

Jalur dengan karakter pengganti dapat mencocokkan beberapa peristiwa dari satu penulisan. Sisipan

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

mencocokkan jalur "/foo/{bar}" dua kali: sekali dengan "hello": "world" dan sekali lagi dengan "firebase": "functions".

Menangani data peristiwa

Saat menangani peristiwa Realtime Database, objek data yang ditampilkan adalah DataSnapshot. Untuk peristiwa onWrite atau onUpdate, parameter pertama adalah objek Change yang berisi dua snapshot yang mewakili status data sebelum dan setelah peristiwa pemicu. Untuk peristiwa onCreate dan onDelete, objek data yang ditampilkan adalah snapshot dari data yang dibuat atau dihapus.

Dalam contoh ini, fungsi mengambil snapshot untuk jalur yang ditentukan sebagai snap, mengubah string di lokasi tersebut menjadi huruf kapital, dan menulis string yang telah diubah tersebut ke 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);
    });

Mengakses informasi autentikasi pengguna

Dari EventContext.auth dan EventContext.authType, Anda dapat mengakses informasi pengguna, termasuk izin, untuk pengguna yang memicu suatu fungsi. Tindakan ini dapat digunakan untuk menegakkan aturan keamanan sehingga fungsi Anda dapat menyelesaikan berbagai operasi sesuai dengan tingkat izin pengguna:

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

Anda juga dapat memanfaatkan informasi autentikasi pengguna untuk "meniru identitas" pengguna dan melakukan operasi tulis atas nama pengguna tersebut. Pastikan untuk menghapus instance aplikasi seperti yang ditunjukkan di bawah ini untuk mencegah masalah serentak:

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

Membaca nilai sebelumnya

Objek Change memiliki properti before yang dapat digunakan untuk memeriksa apa saja yang telah disimpan ke Realtime Database sebelum peristiwa. Properti before menampilkan DataSnapshot yang semua metodenya (misalnya, val() dan exists()) mengacu ke nilai sebelumnya. Anda dapat membaca kembali nilai baru tersebut menggunakan DataSnapshot asli atau membaca properti after. Properti ini di setiap Change adalah DataSnapshot lain yang mewakili status data setelah peristiwa tersebut terjadi.

Misalnya, properti before dapat digunakan untuk memastikan bahwa fungsi hanya mengubah teks menjadi huruf kapital ketika pertama kali dibuat:

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