Aktywatory Cloud Firestore (1 generacji)

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ć za pomocą interfejsu zrzutu dokumentu lub pakietu Admin SDK.

W typowym cyklu życia funkcja Cloud Firestore wykonuje te czynności:

  1. Czeka na zmiany w konkretnym dokumencie.
  2. Uruchamia się, gdy wystąpi zdarzenie, i wykonuje swoje zadania.
  3. Otrzymuje obiekt danych, który zawiera zrzut danych przechowywanych w określonym dokumencie. W przypadku zdarzeń zapisu lub aktualizacji obiekt danych zawiera 2 zrzuty, które reprezentują stan danych przed zdarzeniem wywołującym i po nim.

Odległość między lokalizacją instancji Firestore a lokalizacją funkcji może powodować znaczne opóźnienia sieci. Aby zoptymalizować wydajność, rozważ określenie lokalizacji funkcji, jeśli ma to zastosowanie.

Aktywatory funkcji Cloud Firestore

Pakiet SDK Cloud Functions for Firebase eksportuje obiekt functions.firestore, który umożliwia tworzenie modułów obsługi powiązanych z określonymi zdarzeniami Cloud Firestore.

Typ zdarzenia Aktywator
onCreate Uruchamiana, gdy dokument jest zapisywany po raz pierwszy.
onUpdate Uruchamiane, gdy dokument już istnieje i zmieniła się dowolna wartość.
onDelete Uruchamiane, gdy dokument z danymi zostanie usunięty.
onWrite Wywoływane, gdy wywoływane są reguły onCreate, onUpdate lub onDelete.

Jeśli nie masz jeszcze projektu z włączoną usługą Cloud Functions for Firebase, przeczytaj artykuł Pierwsze kroki: pisanie i wdrażanie pierwszych funkcji, aby dowiedzieć się, jak skonfigurować projekt Cloud Functions for Firebase.

Pisanie funkcji aktywowanych przez Cloud Firestore

Definiowanie aktywatora funkcji

Aby zdefiniować aktywator Cloud Firestore, określ ś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 wieloznacznego.

Określ pojedynczy dokument

Jeśli chcesz wywołać zdarzenie w przypadku dowolnej zmiany w konkretnym 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ślanie grupy dokumentów za pomocą symboli wieloznacznych

Jeśli chcesz dołączyć aktywator do grupy dokumentów, np. do dowolnego dokumentu w określonej kolekcji, zamiast identyfikatora dokumentu użyj {wildcard}:

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 dowolne pole w dowolnym dokumencie w kolekcji users zostanie zmienione, będzie pasować do symbolu wieloznacznego o nazwie userId.

Jeśli dokument w kolekcji users ma podkolekcje i zmieni się pole w dokumencie w jednej z tych podkolekcji, symbol wieloznaczny userId nie zostanie aktywowany.

Dopasowania symboli wieloznacznych są wyodrębniane ze ścieżki dokumentu i przechowywane w 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"}
    });

Aktywatory zdarzeń

Wywoływanie funkcji po utworzeniu nowego dokumentu

Możesz wywołać funkcję za każdym razem, gdy w kolekcji zostanie utworzony nowy dokument, używając 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 ...
    });

Uruchamianie funkcji po zaktualizowaniu dokumentu

Możesz też wywołać funkcję, która zostanie uruchomiona po zaktualizowaniu dokumentu, używając funkcji onUpdate() z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje updateUser, jeśli 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 ...
    });

Uruchamianie funkcji po usunięciu dokumentu

Możesz też wywołać funkcję, gdy dokument zostanie usunięty, używając funkcji onDelete() z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje deleteUser, gdy użytkownik usuwa 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 w przypadku wszystkich zmian w dokumencie

Jeśli nie interesuje Cię typ wywoływanego zdarzenia, możesz nasłuchiwać wszystkich zmian w dokumencie Cloud Firestore za pomocą funkcji onWrite() z symbolem wieloznacznym. Ta przykładowa funkcja wywołuje modifyUser, gdy użytkownik zostanie 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 funkcja udostępnia zrzut danych związanych ze zdarzeniem. Możesz użyć tego zrzutu, aby odczytać lub zapisać dokument, który wywołał zdarzenie, lub użyć pakietu Firebase Admin SDK, aby uzyskać dostęp do innych części bazy danych.

Dane zdarzenia

Dane na temat czytania

Po aktywowaniu funkcji możesz pobrać dane ze zaktualizowanego dokumentu lub dane sprzed aktualizacji. Możesz uzyskać wcześniejsze dane, używając 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();
    });

Dostęp do właściwości możesz uzyskać tak samo jak w przypadku każdego innego obiektu. Możesz też użyć funkcji get, aby uzyskać dostęp do konkretnych pól:

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 konkretnym 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 Cloud Firestore Node.js SDK i zawiera metody takie jak update(), set() i remove(), dzięki którym możesz łatwo zmodyfikować dokument, który wywołał 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 spoza zdarzenia wywołującego

Funkcje Cloud Functions są wykonywane w zaufanym środowisku, co oznacza, że są autoryzowane jako konto usługi w Twoim projekcie. Możesz wykonywać operacje odczytu i zapisu za pomocą pakietu 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({ ... });
  });

Ograniczenia

Pamiętaj o tych ograniczeniach dotyczących aktywatorów Cloud Firestore w Cloud Functions:

  • Cloud Functions (1 generacji) wymaga istniejącej bazy danych „(default)” w trybie natywnym Firestore. Nie obsługuje baz danych o nazwie Cloud Firestore ani trybu Datastore. W takich przypadkach do konfigurowania zdarzeń używaj Cloud Functions (2 generacji).
  • Konfiguracja między projektami z aktywatorami Cloud Functions i Cloud Firestore jest ograniczona. Aby skonfigurować aktywator Cloud Firestore, Cloud Functions musi być w tym samym projekcie.
  • Kolejność nie jest gwarantowana. Szybkie zmiany mogą spowodować wywołanie funkcji w nieoczekiwanej kolejności.
  • Zdarzenia są dostarczane co najmniej raz, ale pojedyncze zdarzenie może spowodować wielokrotne wywołanie funkcji. Unikaj polegania na mechanizmach gwarantujących dostarczenie dokładnie raz i pisz 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żesz utworzyć aktywatora, który pasuje do wielu baz danych.
  • Usunięcie bazy danych nie powoduje automatycznego usunięcia żadnych aktywatorów tej bazy danych. Aktywator przestanie dostarczać zdarzenia, ale będzie nadal istnieć, dopóki go 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 wliczane do wykorzystania logów w projekcie.
    • Te logi znajdziesz w Eksploratorze logów z komunikatem „Nie można dostarczyć zdarzenia do funkcji w Cloud Functions, ponieważ rozmiar przekracza limit dla 1 generacji…” o ważności error. Nazwę funkcji znajdziesz w polu functionName. Jeśli pole receiveTimestamp nadal mieści się w ciągu godziny od teraz, możesz wywnioskować rzeczywistą treść zdarzenia, odczytując dany dokument z migawką przed sygnaturą czasową i po niej.
    • Aby uniknąć takiej sytuacji:
      • Migracja i uaktualnienie do Cloud Functions (2 generacji)
      • Zmniejsz rozmiar dokumentu.
      • Usuń dany element Cloud Functions
    • Możesz wyłączyć samo logowanie za pomocą wykluczeń, ale pamiętaj, że zdarzenia powodujące błędy nadal nie będą dostarczane.