Dengan Cloud Functions, Anda dapat men-deploy kode untuk menangani peristiwa yang dipicu oleh perubahan pada database Cloud Firestore. Dengan begitu, Anda dapat menambahkan fungsionalitas sisi server ke aplikasi dengan mudah tanpa harus menjalankan server Anda sendiri.
Cloud Functions (generasi ke-2)
Dengan dukungan Cloud Run dan Eventarc, Cloud Functions for Firebase (generasi ke-2) memberi Anda infrastruktur yang lebih andal kontrol lanjutan atas performa dan skalabilitas, serta kontrol runtime fungsi yang lebih besar. Untuk mengetahui informasi selengkapnya tentang generasi ke-2, lihat Cloud Functions for Firebase (generasi ke-2). Untuk melihat informasi selengkapnya tentang generasi ke-1, lihat Memperluas Cloud Firestore dengan Cloud Functions.
Pemicu fungsi Cloud Firestore
Cloud Functions for Firebase SDK mengekspor pemicu peristiwa Cloud Firestore berikut untuk memungkinkan Anda membuat pengendali yang terkait dengan peristiwa Cloud Firestore tertentu:
Node.js
Jenis Peristiwa | Pemicu |
---|---|
onDocumentCreated |
Dipicu saat dokumen ditulisi untuk pertama kalinya. |
onDocumentUpdated |
Dipicu saat dokumen sudah ada dan nilainya berubah. |
onDocumentDeleted |
Dipicu saat dokumen dihapus. |
onDocumentWritten |
Dipicu saat onDocumentCreated , onDocumentUpdated , atau onDocumentDeleted dipicu. |
Python (pratinjau)
Jenis Peristiwa | Pemicu |
---|---|
on_document_created |
Dipicu saat dokumen ditulisi untuk pertama kalinya. |
on_document_updated |
Dipicu saat dokumen sudah ada dan nilainya berubah. |
on_document_deleted |
Dipicu saat dokumen dihapus. |
on_document_written |
Dipicu saat on_document_created , on_document_updated , atau on_document_deleted dipicu. |
Peristiwa Cloud Firestore hanya dipicu jika ada perubahan dokumen. Pembaruan terhadap dokumen Cloud Firestore yang tidak mengubah data (penulisan tanpa pengoperasian), tidak menghasilkan peristiwa penulisan atau pembaruan. Peristiwa tidak dapat ditambahkan ke kolom tertentu.
Jika Anda belum mengaktifkan project untuk Cloud Functions for Firebase, baca Memulai Cloud Functions for Firebase (generasi ke-2) untuk mengonfigurasi dan menyiapkan Cloud Functions Anda untuk project Firebase.
Menulis fungsi yang dipicu oleh Cloud Firestore
Mendefinisikan pemicu fungsi
Untuk mendefinisikan pemicu Cloud Firestore, tentukan jalur dokumen dan jenis peristiwa:
Node.js
import {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("my-collection/{docId}", (event) => {
/* ... */
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_created,
on_document_deleted,
on_document_updated,
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_created(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot]) -> None:
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
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("users/marie", (event) => {
// Your code here
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/marie")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
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
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("users/{userId}", (event) => {
// If we set `/users/marie` to {name: "Marie"} then
// event.params.userId == "marie"
// ... and ...
// event.data.after.data() == {name: "Marie"}
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# If we set `/users/marie` to {name: "Marie"} then
event.params["userId"] == "marie" # True
# ... and ...
event.data.after.to_dict() == {"name": "Marie"} # True
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 event.params
.
Anda dapat mendefinisikan sebanyak mungkin karakter pengganti yang diinginkan untuk menggantikan ID dokumen atau koleksi eksplisit, misalnya:
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("users/{userId}/{messageCollectionId}/{messageId}", (event) => {
// If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
// event.params.userId == "marie";
// event.params.messageCollectionId == "incoming_messages";
// event.params.messageId == "134";
// ... and ...
// event.data.after.data() == {body: "Hello"}
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}/{messageCollectionId}/{messageId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# If we set `/users/marie/incoming_messages/134` to {body: "Hello"} then
event.params["userId"] == "marie" # True
event.params["messageCollectionId"] == "incoming_messages" # True
event.params["messageId"] == "134" # True
# ... and ...
event.data.after.to_dict() == {"body": "Hello"}
Pemicu Anda harus selalu menunjuk ke sebuah dokumen, meskipun Anda menggunakan karakter pengganti.
Misalnya, users/{userId}/{messageCollectionId}
tidak valid karena {messageCollectionId}
adalah sebuah koleksi. Namun, users/{userId}/{messageCollectionId}/{messageId}
valid
karena {messageId}
akan selalu mengarah ke dokumen.
Pemicu Peristiwa
Memicu fungsi saat dokumen baru dibuat
Anda dapat memicu fungsi agar aktif setiap kali ada dokumen baru yang dibuat dalam koleksi. Fungsi contoh ini akan terpicu setiap kali profil pengguna baru ditambahkan:
Node.js
import {
onDocumentCreated,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.createuser = onDocumentCreated("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const snapshot = event.data;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// access a particular field as you would any JS property
const name = data.name;
// perform more operations ...
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_created,
Event,
DocumentSnapshot,
)
@on_document_created(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot]) -> None:
# Get a dictionary representing the document
# e.g. {'name': 'Marie', 'age': 66}
new_value = event.data.to_dict()
# Access a particular field as you would any dictionary
name = new_value["name"]
# Perform more operations ...
Memicu fungsi saat dokumen diperbarui
Anda juga dapat memicu fungsi agar aktif saat dokumen diperbarui. Fungsi contoh ini akan aktif jika pengguna mengubah profilnya:
Node.js
import {
onDocumentUpdated,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.updateuser = onDocumentUpdated("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = event.data.after.data();
// access a particular field as you would any JS property
const name = newValue.name;
// perform more operations ...
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_updated,
Event,
Change,
DocumentSnapshot,
)
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get a dictionary representing the document
# e.g. {'name': 'Marie', 'age': 66}
new_value = event.data.after.to_dict()
# Access a particular field as you would any dictionary
name = new_value["name"]
# Perform more operations ...
Memicu fungsi saat dokumen dihapus
Anda juga dapat memicu fungsi saat dokumen dihapus. Fungsi contoh ini akan aktif ketika pengguna menghapus profilnya:
Node.js
import {
onDocumentDeleted,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.deleteuser = onDocumentDeleted("users/{userId}", (event) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const snap = event.data;
const data = snap.data();
// perform more operations ...
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_deleted,
Event,
DocumentSnapshot,
)
@on_document_deleted(document="users/{userId}")
def myfunction(event: Event[DocumentSnapshot|None]) -> None:
# Perform more 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 pemicu peristiwa "dokumen yang ditulis". Fungsi contoh ini akan diaktifkan jika pengguna dibuat, diperbarui, atau dihapus:
Node.js
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.modifyuser = onDocumentWritten("users/{userId}", (event) => {
// Get an object with the current document values.
// If the document does not exist, it was deleted
const document = event.data.after.data();
// Get an object with the previous document values
const previousValues = event.data.before.data();
// perform more operations ...
});
Python (pratinjau)
from firebase_functions.firestore_fn import (
on_document_written,
Event,
Change,
DocumentSnapshot,
)
@on_document_written(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot | None]]) -> None:
# Get an object with the current document values.
# If the document does not exist, it was deleted.
document = (event.data.after.to_dict()
if event.data.after is not None else None)
# Get an object with the previous document values.
# If the document does not exist, it was newly created.
previous_values = (event.data.before.to_dict()
if event.data.before is not None else None)
# Perform more 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 event.data.before
, yang berisi snapshot dokumen sebelum pembaruan.
Demikian pula, event.data.after
berisi status snapshot dokumen setelah pembaruan.
Node.js
exports.updateuser2 = onDocumentUpdated("users/{userId}", (event) => {
// Get an object with the current document values.
// If the document does not exist, it was deleted
const newValues = event.data.after.data();
// Get an object with the previous document values
const previousValues = event.data.before.data();
});
Python (pratinjau)
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get an object with the current document values.
new_value = event.data.after.to_dict()
# Get an object with the previous document values.
prev_value = event.data.before.to_dict()
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 = event.data.after.data().age;
const name = event.data.after.data()['name'];
// Fetch data using built in accessor
const experience = event.data.after.data.get('experience');
Python (pratinjau)
# Get the value of a single document field.
age = event.data.after.get("age")
# Convert the document to a dictionary.
age = event.data.after.to_dict()["age"]
Menulis Data
Setiap pemanggilan fungsi dikaitkan dengan dokumen tertentu dalam database Cloud Firestore. Anda dapat mengakses dokumen tersebut di ringkasan yang ditampilkan ke fungsi Anda.
Referensi dokumen menyertakan metode seperti update()
, set()
, dan remove()
sehingga Anda dapat mengubah dokumen yang memicu fungsi.
Node.js
import { onDocumentUpdated } from "firebase-functions/v2/firestore";
exports.countnamechanges = onDocumentUpdated('users/{userId}', (event) => {
// Retrieve the current and previous value
const data = event.data.after.data();
const previousData = event.data.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 data.after.ref.set({
name_change_count: count + 1
}, {merge: true});
});
Python (pratinjau)
@on_document_updated(document="users/{userId}")
def myfunction(event: Event[Change[DocumentSnapshot]]) -> None:
# Get the current and previous document values.
new_value = event.data.after
prev_value = event.data.before
# We'll only update if the name has changed.
# This is crucial to prevent infinite loops.
if new_value.get("name") == prev_value.get("name"):
return
# Retrieve the current count of name changes
count = new_value.to_dict().get("name_change_count", 0)
# Update the count
new_value.reference.update({"name_change_count": count + 1})
```
Data di luar peristiwa pemicu
Cloud Functions dijalankan dalam lingkungan tepercaya. Alat tersebut diotorisasi sebagai akun layanan di project Anda, dan Anda dapat melakukan pembacaan dan penulisan menggunakan Firebase Admin SDK:
Node.js
const { initializeApp } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
initializeApp();
const db = getFirestore();
exports.writetofirestore = onDocumentWritten("some/doc", (event) => {
db.doc('some/otherdoc').set({ ... });
});
exports.writetofirestore = onDocumentWritten('users/{userId}', (event) => {
db.doc('some/otherdoc').set({
// Update otherdoc
});
});
Python (pratinjau)
from firebase_admin import firestore, initialize_app
import google.cloud.firestore
initialize_app()
@on_document_written(document="some/doc")
def myfunction(event: Event[Change[DocumentSnapshot | None]]) -> None:
firestore_client: google.cloud.firestore.Client = firestore.client()
firestore_client.document("another/doc").set({
# ...
})
Keterbatasan
Perhatikan batasan berikut untuk pemicu Cloud Firestore untuk Cloud Functions:
- 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.
- Cloud Functions (generasi ke-1) hanya berfungsi dengan database "(default)" dan tidak mendukung database bernama Cloud Firestore. Gunakan Cloud Functions (generasi ke-2) untuk mengonfigurasi peristiwa untuk database bernama.
- 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 kolomfunctionName
. Jika kolomreceiveTimestamp
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:
- Melakukan migrasi dan upgrade ke Cloud Functions (generasi ke-2)
- Memperkecil dokumen
- Menghapus Cloud Functions yang dimaksud
- Anda dapat menonaktifkan logging itu sendiri menggunakan pengecualian, tetapi perhatikan bahwa peristiwa yang melanggar tidak akan dikirim.