Dzięki Cloud Functions możesz obsługiwać zdarzenia w Cloud Firestore bez konieczności aktualizowania kodu klienta. Zmiany w Cloud Firestore możesz wprowadzać, korzystając z interfejsu zrzutu dokumentów lub pakietu Admin SDK.
W typowym cyklu życia funkcja Cloud Firestore wykonuje te czynności:
- Oczekiwanie na zmiany w konkretnym dokumencie.
- Jest aktywowany, gdy zdarzenie następuje i wykonuje swoje zadania.
- Odbiera obiekt danych zawierający zrzut danych przechowywanych w określonym dokumencie. W przypadku zapisu lub aktualizacji zdarzeń obiekt danych zawiera 2 zrzuty obrazujące stan danych przed zdarzeniem wywołującym i po nim.
Odległość między lokalizacją instancji Firestore a lokalizacją funkcji może być przyczyną znacznego opóźnienia w sieci. Aby zoptymalizować wydajność, w razie potrzeby określ lokalizację funkcji.
Aktywatory funkcji Cloud Firestore
Pakiet SDK Cloud Functions dla Firebase wyeksportuje obiekt functions.firestore
, który umożliwia tworzenie modułów obsługi powiązanych z określonymi zdarzeniami Cloud Firestore.
Typ zdarzenia | Aktywator |
---|---|
onCreate |
Wywoływane, gdy dokument jest zapisany po raz pierwszy. |
onUpdate |
Wywoływane, gdy dokument już istnieje, ale jego wartość uległa zmianie. |
onDelete |
Wywoływane po usunięciu dokumentu z danymi. |
onWrite |
Wywoływane po wywołaniu funkcji onCreate , onUpdate lub onDelete . |
Jeśli nie masz jeszcze projektu, w którym włączono Cloud Functions dla Firebase, przeczytaj artykuł Pierwsze kroki: tworzenie i wdrażanie pierwszych funkcji, aby skonfigurować i skonfigurować projekt Cloud Functions dla Firebase.
Jak pisać funkcje aktywowane przez Cloud Firestore
Zdefiniuj aktywator funkcji
Aby zdefiniować aktywator Cloud Firestore, podaj ścieżkę dokumentu i typ zdarzenia:
Node.js
const functions = require('firebase-functions');
exports.myFunction = functions.firestore
.document('my-collection/{docId}')
.onWrite((change, context) => { /* ... */ });
Ścieżki dokumentów mogą odwoływać się do konkretnego dokumentu lub wzorca z symbolami wieloznacznymi.
Wskaż pojedynczy dokument
Jeśli chcesz wywoływać zdarzenie w przypadku dowolnej zmiany w określonym dokumencie, możesz użyć tej funkcji.
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 });
Określ grupę dokumentów przy użyciu symboli wieloznacznych
Jeśli chcesz dołączyć regułę do grupy dokumentów, na przykład dowolnego dokumentu w określonej kolekcji, użyj {wildcard}
zamiast identyfikatora dokumentu:
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"} });
W tym przykładzie, gdy zmieni się dowolne pole w dowolnym dokumencie w users
, odpowiada ono symbolowi wieloznacznym o nazwie userId
.
Jeśli dokument w kolekcji users
zawiera kolekcje podrzędne, a pole w jednym z takich dokumentów zostanie zmienione, symbol wieloznaczny userId
nie zostanie wywołany.
Dopasowania zawierające symbole wieloznaczne są wyodrębniane ze ścieżki dokumentu i przechowywane w elemencie context.params
.
Możesz zdefiniować dowolną liczbę symboli wieloznacznych, aby zastąpić jawne identyfikatory kolekcji lub dokumentów, na przykład:
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"} });
Wyzwalacze zdarzeń
Aktywuj funkcję podczas tworzenia nowego dokumentu
Możesz uruchomić funkcję za każdym razem, gdy w kolekcji zostanie utworzony nowy dokument, przy użyciu modułu obsługi onCreate()
z symbolem wieloznacznym.
Ta przykładowa funkcja wywołuje createUser
za każdym razem, gdy dodawany jest nowy profil użytkownika:
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 ... });
Wywoływanie funkcji po zaktualizowaniu dokumentu
Możesz też aktywować funkcję uruchamiania po zaktualizowaniu dokumentu za pomocą funkcji onUpdate()
z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje updateUser
, gdy użytkownik zmieni swój profil:
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 ... });
Aktywowanie funkcji po usunięciu dokumentu
Możesz też aktywować funkcję w przypadku usunięcia dokumentu za pomocą funkcji onDelete()
z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje deleteUser
, gdy użytkownik usunie swój profil:
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 ... });
Aktywowanie funkcji przy wszystkich zmianach w dokumencie
Jeśli typ wywoływanego zdarzenia nie jest dla Ciebie ważny, możesz nasłuchiwać wszystkich zmian w dokumencie Cloud Firestore za pomocą funkcji onWrite()
z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje modifyUser
, jeśli użytkownik został utworzony, zaktualizowany lub usunięty:
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 ... });
Odczytywanie i zapisywanie danych
Po aktywowaniu funkcji udostępnia zrzut danych związanych ze zdarzeniem. Możesz użyć tego zrzutu, aby odczytywać dokument, który wywołał zdarzenie, lub w nim zapisywać. Możesz też skorzystać z pakietu Firebase Admin SDK, aby uzyskać dostęp do innych części swojej bazy danych.
Dane zdarzenia
Odczytywanie danych
Po wywołaniu funkcji możesz chcieć pobrać dane ze zaktualizowanego dokumentu lub pobrać dane przed aktualizacją. Wcześniejsze dane możesz uzyskać, używając parametru change.before.data()
, który zawiera migawkę dokumentu sprzed aktualizacji.
Podobnie change.after.data()
zawiera stan zrzutu dokumentu po aktualizacji.
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(); });
Możesz uzyskać dostęp do właściwości tak samo jak w przypadku każdego innego obiektu. Aby uzyskać dostęp do określonych pól, możesz też użyć funkcji get
:
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');
Zapisywanie danych
Każde wywołanie funkcji jest powiązane z określonym dokumentem w bazie danych Cloud Firestore. Możesz uzyskać dostęp do tego dokumentu jako DocumentReference
we właściwości ref
zrzutu zwróconego do funkcji.
Ten obiekt DocumentReference
pochodzi z pakietu SDK Cloud Firestore Node.js i zawiera metody takie jak update()
, set()
i remove()
, dzięki czemu można łatwo zmodyfikować dokument, który uruchomił funkcję.
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}); });
Dane poza zdarzeniem aktywującym
Funkcje w Cloud Functions są wykonywane w zaufanym środowisku, co oznacza, że są autoryzowane jako konto usługi w projekcie. Odczyty i zapisy możesz wykonywać za pomocą pakietu SDK Firebase Admin:
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({ ... });
});
Ograniczenia
Zwróć uwagę na te ograniczenia aktywatorów Cloud Firestore dla Cloud Functions:
- Cloud Functions (1 generacji) wymaga utworzenia istniejącej „(domyślnej)” bazy danych w trybie natywnym Firestore. Nie obsługuje nazwanych baz danych Cloud Firestore ani trybu Datastore. W takich przypadkach używaj Cloud Functions (2 generacji), aby konfigurować zdarzenia.
- Zamówienie nie jest gwarantowane. Szybkie zmiany mogą aktywować wywołania funkcji w nieoczekiwanej kolejności.
- Zdarzenia są dostarczane co najmniej raz, ale pojedyncze zdarzenie może powodować wiele wywołań funkcji. Unikaj polegania na mechanice „dokładnie raz” i zapisz funkcje idempotentne.
- Cloud Firestore w trybie Datastore wymaga Cloud Functions (2 generacji). Cloud Functions (1 generacji) nie obsługuje trybu Datastore.
- Aktywator jest powiązany z jedną bazą danych. Nie można utworzyć aktywatora pasującego do wielu baz danych.
- Usunięcie bazy danych nie powoduje automatycznego usunięcia żadnych jej aktywatorów. Reguła przestanie dostarczać zdarzenia, ale będzie istnieć, dopóki jej nie usuniesz.
- Jeśli dopasowane zdarzenie przekracza maksymalny rozmiar żądania, może nie zostać dostarczone do Cloud Functions (1 generacji).
- Zdarzenia, które nie zostały dostarczone z powodu rozmiaru żądania, są rejestrowane w logach platformy i uwzględniane w dzienniku projektu.
- Te logi znajdziesz w eksploratorze logów z komunikatem „Zdarzenie nie może dostarczyć do funkcji w Cloud Functions z powodu przekroczenia limitu dla 1 generacji...” o poziomie ważności
error
. Nazwę funkcji znajdziesz pod polemfunctionName
. Jeśli zawartość polareceiveTimestamp
będzie jeszcze w ciągu godziny, możesz wywnioskować faktyczną treść zdarzenia, odczytując dany dokument z migawką przed sygnaturą czasową i po niej. - Aby tego uniknąć:
- Migracja i przejście na Cloud Functions (2 generacji)
- Zmniejsz rozmiar dokumentu
- Usuń te funkcje w Cloud Functions
- Możesz samodzielnie wyłączyć logowanie przy użyciu wykluczeń, ale pamiętaj, że zdarzenia naruszające zasady nadal nie będą dostarczane.