Pemicu Cloud Firestore


Dengan Cloud Functions, Anda dapat menangani peristiwa di Cloud Firestore tanpa harus memperbarui kode klien. Anda dapat membuat perubahan pada Cloud Firestore melalui antarmuka ringkasan dokumen atau melalui Admin SDK.

Dalam siklus proses umum, fungsi Cloud Firestore melakukan hal-hal berikut:

  1. Menunggu perubahan pada dokumen tertentu.
  2. Terpicu ketika suatu peristiwa terjadi dan menjalankan tugasnya.
  3. Menerima objek data yang berisi snapshot data yang disimpan dalam dokumen yang ditentukan. Untuk peristiwa operasi tulis atau pembaruan, objek data berisi dua snapshot yang mewakili status data sebelum dan setelah peristiwa pemicu.

Jarak antara lokasi instance Firestore dan lokasi fungsi dapat menyebabkan latensi jaringan yang signifikan. Untuk mengoptimalkan performa, sebaiknya tentukan lokasi fungsi, jika bisa diterapkan.

Pemicu fungsi Cloud Firestore

Cloud Functions for Firebase SDK mengekspor objek functions.firestore, sehingga Anda dapat membuat pengendali yang terikat dengan peristiwa Cloud Firestore tertentu.

Jenis Peristiwa Pemicu
onCreate Dipicu saat dokumen ditulisi untuk pertama kalinya.
onUpdate Dipicu saat dokumen sudah ada dan nilainya berubah.
onDelete Dipicu saat dokumen yang memuat data dihapus.
onWrite Dipicu saat onCreate, onUpdate, atau onDelete dipicu.

Jika Anda belum memiliki project yang diaktifkan untuk Cloud Functions for Firebase, baca Memulai: Menulis dan Men-deploy Fungsi Pertama Anda untuk mengonfigurasi dan menyiapkan project Cloud Functions for Firebase.

Menulis fungsi yang dipicu oleh Cloud Firestore

Mendefinisikan pemicu fungsi

Untuk mendefinisikan pemicu Cloud Firestore, tentukan jalur dokumen dan jenis peristiwa:

Node.js

const functions = require('firebase-functions');

exports.myFunction = functions.firestore
  .document('my-collection/{docId}')
  .onWrite((change, context) => { /* ... */ });

Jalur dokumen dapat merujuk pada dokumen tertentu atau pola karakter pengganti.

Menentukan satu dokumen

Jika ingin memicu suatu peristiwa untuk perubahan apa pun pada dokumen tertentu, Anda dapat menggunakan fungsi berikut.

Node.js

// Listen for any change on document `marie` in collection `users`
exports.myFunctionName = functions.firestore
    .document('users/marie').onWrite((change, context) => {
      // ... Your code here
    });

Menentukan grup dokumen menggunakan karakter pengganti

Jika ingin menambahkan pemicu ke grup dokumen, seperti dokumen dalam koleksi tertentu, gunakan {wildcard} sebagai pengganti ID dokumen:

Node.js

// Listen for changes in all documents in the 'users' collection
exports.useWildcard = functions.firestore
    .document('users/{userId}')
    .onWrite((change, context) => {
      // If we set `/users/marie` to {name: "Marie"} then
      // context.params.userId == "marie"
      // ... and ...
      // change.after.data() == {name: "Marie"}
    });

Dalam contoh ini, saat kolom dalam dokumen pada users diubah, sistem akan mencocokkannya dengan karakter pengganti yang disebut userId.

Jika dokumen dalam users memiliki subkoleksi, dan kolom di salah satu dokumen subkoleksi tersebut diubah, karakter pengganti userId tidak akan terpicu.

Kecocokan karakter pengganti diekstrak dari jalur dokumen dan disimpan ke dalam context.params. Anda dapat mendefinisikan sebanyak mungkin karakter pengganti yang diinginkan untuk menggantikan ID dokumen atau koleksi eksplisit, misalnya:

Node.js

// Listen for changes in all documents in the 'users' collection and all subcollections
exports.useMultipleWildcards = functions.firestore
    .document('users/{userId}/{messageCollectionId}/{messageId}')
    .onWrite((change, context) => {
      // If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
      // context.params.userId == "marie";
      // context.params.messageCollectionId == "incoming_messages";
      // context.params.messageId == "134";
      // ... and ...
      // change.after.data() == {body: "Hello"}
    });

Pemicu Peristiwa

Memicu fungsi saat dokumen baru dibuat

Anda dapat memicu fungsi agar aktif setiap kali ada dokumen baru yang dibuat dalam koleksi menggunakan pengendali onCreate() dengan karakter pengganti. Fungsi contoh ini akan memanggil createUser setiap kali profil pengguna baru ditambahkan:

Node.js

exports.createUser = functions.firestore
    .document('users/{userId}')
    .onCreate((snap, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = snap.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Memicu fungsi saat dokumen diperbarui

Anda juga dapat memicu fungsi agar aktif saat dokumen diperbarui menggunakan fungsi onUpdate() dengan karakter pengganti. Fungsi contoh ini akan memanggil updateUser jika pengguna mengubah profilnya:

Node.js

exports.updateUser = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the document
      // e.g. {'name': 'Marie', 'age': 66}
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();

      // access a particular field as you would any JS property
      const name = newValue.name;

      // perform desired operations ...
    });

Memicu fungsi saat dokumen dihapus

Anda juga dapat memicu fungsi saat dokumen dihapus menggunakan fungsi onDelete() dengan karakter pengganti. Fungsi contoh ini akan memanggil deleteUser ketika pengguna menghapus profilnya:

Node.js

exports.deleteUser = functions.firestore
    .document('users/{userID}')
    .onDelete((snap, context) => {
      // Get an object representing the document prior to deletion
      // e.g. {'name': 'Marie', 'age': 66}
      const deletedValue = snap.data();

      // perform desired operations ...
    });

Memicu fungsi untuk semua perubahan pada dokumen

Jika tidak mementingkan jenis peristiwa yang diaktifkan, Anda dapat memproses semua perubahan dalam dokumen Cloud Firestore menggunakan fungsi onWrite() dengan karakter pengganti. Fungsi contoh ini akan memanggil modifyUser ketika pengguna dibuat, diperbarui, atau dihapus:

Node.js

exports.modifyUser = functions.firestore
    .document('users/{userID}')
    .onWrite((change, context) => {
      // Get an object with the current document value.
      // If the document does not exist, it has been deleted.
      const document = change.after.exists ? change.after.data() : null;

      // Get an object with the previous document value (for update or delete)
      const oldDocument = change.before.data();

      // perform desired operations ...
    });

Membaca dan Menulis Data

Jika dipicu, suatu fungsi akan menghasilkan snapshot data yang terkait dengan peristiwa tersebut. Anda dapat menggunakan snapshot ini untuk membaca atau menulis dokumen yang memicu peristiwa tersebut, atau menggunakan Firebase Admin SDK untuk mengakses bagian lain database Anda.

Data Peristiwa

Membaca Data

Saat sebuah fungsi dipicu, Anda mungkin ingin mendapatkan data dari dokumen sesudah atau sebelum pembaruan. Anda bisa mendapatkan data sebelumnya menggunakan change.before.data(), yang berisi snapshot dokumen sebelum pembaruan. Demikian pula, change.after.data() berisi status snapshot dokumen setelah pembaruan.

Node.js

exports.updateUser2 = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Get an object representing the current document
      const newValue = change.after.data();

      // ...or the previous value before this update
      const previousValue = change.before.data();
    });

Anda dapat mengakses properti sebagaimana Anda mengakses properti pada objek lainnya. Atau, Anda dapat menggunakan fungsi get untuk mengakses kolom tertentu:

Node.js

// Fetch data using standard accessors
const age = snap.data().age;
const name = snap.data()['name'];

// Fetch data using built in accessor
const experience = snap.get('experience');

Menulis Data

Setiap pemanggilan fungsi dikaitkan dengan dokumen tertentu dalam database Cloud Firestore. Anda dapat mengakses dokumen tersebut sebagai DocumentReference di properti ref pada snapshot yang ditampilkan ke fungsi Anda.

DocumentReference ini berasal dari Cloud Firestore Node.js SDK dan mencakup berbagai metode seperti update(), set(), dan remove(), sehingga Anda dapat dengan mudah mengubah dokumen yang memicu fungsi tersebut.

Node.js

// Listen for updates to any `user` document.
exports.countNameChanges = functions.firestore
    .document('users/{userId}')
    .onUpdate((change, context) => {
      // Retrieve the current and previous value
      const data = change.after.data();
      const previousData = change.before.data();

      // We'll only update if the name has changed.
      // This is crucial to prevent infinite loops.
      if (data.name == previousData.name) {
        return null;
      }

      // Retrieve the current count of name changes
      let count = data.name_change_count;
      if (!count) {
        count = 0;
      }

      // Then return a promise of a set operation to update the count
      return change.after.ref.set({
        name_change_count: count + 1
      }, {merge: true});
    });

Data di luar peristiwa pemicu

Cloud Functions dijalankan dalam lingkungan tepercaya, yang berarti diotorisasi sebagai akun layanan di project Anda. Anda dapat melakukan pembacaan dan penulisan menggunakan Firebase Admin SDK:

Node.js

const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();

exports.writeToFirestore = functions.firestore
  .document('some/doc')
  .onWrite((change, context) => {
    db.doc('some/otherdoc').set({ ... });
  });

Batasan

Perhatikan batasan berikut untuk pemicu Cloud Firestore untuk Cloud Functions:

  • Cloud Functions (generasi ke-1) hanya dapat digunakan dengan database "(default)" yang sudah dibuat dengan mode native Firestore. Teknologi ini tidak mendukung mode Datastore atau database bernama Cloud Firestore. Gunakan Cloud Functions (generasi ke-2) untuk mengonfigurasi peristiwa dalam kasus tersebut.
  • Pengurutan tidak dijamin. Perubahan cepat dapat memicu pemanggilan fungsi dalam urutan yang tidak terduga.
  • Peristiwa dikirim setidaknya satu kali, tetapi satu peristiwa dapat menghasilkan beberapa pemanggilan fungsi. Hindari mengandalkan mekanisme tepat satu kali, dan tulis fungsi idempoten.
  • Cloud Firestore dalam mode Datastore memerlukan Cloud Functions (generasi ke-2). Cloud Functions (generasi ke-1) tidak mendukung mode Datastore.
  • Pemicu dikaitkan dengan satu database. Anda tidak dapat membuat pemicu yang cocok dengan beberapa database.
  • Menghapus database tidak secara otomatis menghapus pemicu untuk database tersebut. Pemicu berhenti mengirim peristiwa, tetapi akan tetap ada sampai Anda menghapus pemicu.
  • Jika peristiwa yang cocok melebihi ukuran permintaan maksimum, peristiwa tersebut mungkin tidak akan dikirim ke Cloud Functions (generasi ke-1).
    • Peristiwa yang tidak terkirim karena ukuran permintaan akan dicatat dalam log platform dan diperhitungkan terhadap penggunaan log untuk project.
    • Anda dapat menemukan log ini di Logs Explorer dengan pesan "Event dapat mengirim ke Cloud function karena ukuran melebihi batas untuk generasi ke-1..." dengan tingkat keparahan error. Anda dapat menemukan nama fungsi di bawah kolom functionName. Jika kolom receiveTimestamp masih berada dalam waktu satu jam dari sekarang, Anda dapat menyimpulkan konten peristiwa yang sebenarnya dengan membaca dokumen yang dimaksud menggunakan snapshot sebelum dan setelah stempel waktu.
    • Untuk menghindari peristiwa seperti ini, Anda dapat:
      • Migrasikan dan upgrade ke Cloud Functions (generasi ke-2)
      • Memperkecil dokumen
      • Hapus Cloud Functions yang dimaksud
    • Anda dapat menonaktifkan logging itu sendiri menggunakan pengecualian, tetapi perhatikan bahwa peristiwa yang melanggar tidak akan dikirim.