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)
Didukung oleh 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 terikat 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. |
onDocumentCreatedWithAuthContext |
onDocumentCreated dengan informasi autentikasi tambahan |
onDocumentWrittenWithAuthContext |
onDocumentWritten dengan informasi autentikasi tambahan |
onDocumentDeletedWithAuthContext |
onDocumentDeleted dengan informasi autentikasi tambahan |
onDocumentUpdatedWithAuthContext |
onDocumentUpdated dengan informasi autentikasi tambahan |
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. |
on_document_created_with_auth_context |
on_document_created dengan informasi autentikasi tambahan |
on_document_updated_with_auth_context |
on_document_updated dengan informasi autentikasi tambahan |
on_document_deleted_with_auth_context |
on_document_deleted dengan informasi autentikasi tambahan |
on_document_written_with_auth_context |
on_document_written dengan informasi autentikasi tambahan |
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 memiliki project yang diaktifkan untuk Cloud Functions for Firebase, baca Mulai menggunakan Cloud Functions for Firebase (generasi ke-2) untuk mengonfigurasi dan menyiapkan project Cloud Functions for Firebase Anda.
Menulis fungsi yang dipicu Cloud Firestore
Mendefinisikan pemicu fungsi
Untuk menentukan 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 ...
});
Untuk informasi autentikasi tambahan, gunakan onDocumentCreatedWithAuthContext
.
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 ...
});
Untuk informasi autentikasi tambahan, gunakan onDocumentUpdatedWithAuthContext
.
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 ...
});
Untuk informasi autentikasi tambahan, gunakan onDocumentDeletedWithAuthContext
.
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 ...
});
Untuk informasi autentikasi tambahan, gunakan onDocumentWrittenWithAuthContext
.
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})
Mengakses informasi autentikasi pengguna
Jika menggunakan salah satu jenis peristiwa berikut, Anda dapat mengakses informasi autentikasi pengguna tentang akun utama yang memicu peristiwa tersebut. Informasi ini merupakan tambahan untuk informasi yang ditampilkan dalam peristiwa dasar.
Node.js
onDocumentCreatedWithAuthContext
onDocumentWrittenWithAuthContext
onDocumentDeletedWithAuthContext
onDocumentUpdatedWithAuthContext
Python (pratinjau)
on_document_created_with_auth_context
on_document_updated_with_auth_context
on_document_deleted_with_auth_context
on_document_written_with_auth_context
Untuk informasi tentang data yang tersedia dalam konteks autentikasi, lihat Konteks Autentikasi. Contoh berikut menunjukkan cara mengambil informasi autentikasi:
Node.js
import { onDocumentWrittenWithAuthContext } from "firebase-functions/v2/firestore"
exports.syncUser = onDocumentWrittenWithAuthContext("users/{userId}", (event) => {
const snapshot = event.data.after;
if (!snapshot) {
console.log("No data associated with the event");
return;
}
const data = snapshot.data();
// retrieve auth context from event
const { authType, authId } = event;
let verified = false;
if (authType === "system") {
// system-generated users are automatically verified
verified = true;
} else if (authType === "unknown" || authType === "unauthenticated") {
// admin users from a specific domain are verified
if (authId.endsWith("@example.com")) {
verified = true;
}
}
return data.after.ref.set({
created_by: authId,
verified,
}, {merge: true});
});
Python (pratinjau)
@on_document_updated_with_auth_context(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
# Get the auth context from the event
user_auth_type = event.auth_type
user_auth_id = event.auth_id
Data di luar peristiwa pemicu
Cloud Functions dieksekusi 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({
# ...
})
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 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:
- 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.