Catch up on highlights from Firebase at Google I/O 2023. Learn more

Триггеры Cloud Firestore


С помощью облачных функций вы можете обрабатывать события в Cloud Firestore без необходимости обновлять клиентский код. Вы можете вносить изменения в Cloud Firestore через интерфейс моментального снимка документа или через Admin SDK .

В типичном жизненном цикле функция Cloud Firestore выполняет следующие действия:

  1. Ожидает изменений в конкретном документе.
  2. Запускается при возникновении события и выполняет свои задачи.
  3. Получает объект данных, содержащий моментальный снимок данных, хранящихся в указанном документе. Для событий записи или обновления объект данных содержит два моментальных снимка, которые представляют состояние данных до и после инициирующего события.

Расстояние между расположением экземпляра Firestore и расположением функции может привести к значительной задержке в сети. Чтобы оптимизировать производительность, рассмотрите возможность указания местоположения функции , где это применимо.

Триггеры функции Cloud Firestore

Cloud Functions для Firebase SDK экспортирует объект functions.firestore , который позволяет создавать обработчики, привязанные к определенным событиям Cloud Firestore.

Тип события Курок
onCreate Запускается, когда документ записывается в первый раз.
onUpdate Запускается, когда документ уже существует и любое значение изменено.
onDelete Срабатывает при удалении документа с данными.
onWrite Запускается, когда запускается onCreate , onUpdate или onDelete .

Если у вас еще нет проекта с включенными облачными функциями для Firebase, прочтите статью Начало работы: напишите и разверните свои первые функции , чтобы настроить и настроить проект облачных функций для Firebase.

Написание функций, запускаемых Cloud Firestore

Определить триггер функции

Чтобы определить триггер Cloud Firestore, укажите путь к документу и тип события:

Node.js

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

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

Пути к документам могут ссылаться либо на конкретный документ , либо на подстановочный знак .

Укажите один документ

Если вы хотите инициировать событие для любого изменения в конкретном документе, вы можете использовать следующую функцию.

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
    });

Укажите группу документов с помощью подстановочных знаков

Если вы хотите прикрепить триггер к группе документов, например к любому документу в определенной коллекции, используйте {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"}
    });

В этом примере при изменении любого поля в любом документе users оно соответствует подстановочному знаку с именем userId .

Если документ users имеет вложенные коллекции, а поле в одном из документов этих вложенных коллекций изменено, подстановочный знак userId не срабатывает.

Совпадения с подстановочными знаками извлекаются из пути к документу и сохраняются в context.params . Вы можете определить любое количество подстановочных знаков для замены явных идентификаторов коллекций или документов, например:

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"}
    });

Триггеры событий

Запуск функции при создании нового документа

Вы можете запускать функцию каждый раз, когда в коллекции создается новый документ, используя обработчик onCreate() с подстановочным знаком . В этом примере функция вызывает createUser каждый раз, когда добавляется новый профиль пользователя:

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 ...
    });

Запуск функции при обновлении документа

Вы также можете вызвать функцию для запуска при обновлении документа с помощью функции onUpdate() с подстановочным знаком . В этом примере функция вызывает updateUser если пользователь меняет свой профиль:

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 ...
    });

Активировать функцию при удалении документа

Вы также можете вызвать функцию при удалении документа, используя функцию onDelete() с подстановочным знаком . В этом примере функция вызывает deleteUser , когда пользователь удаляет свой профиль:

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 ...
    });

Активировать функцию для всех изменений в документе

Если вас не волнует тип запускаемого события, вы можете прослушивать все изменения в документе Cloud Firestore, используя функцию onWrite() с подстановочным знаком . В этом примере функция вызывает modifyUser если пользователь создан, обновлен или удален:

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 ...
    });

Чтение и запись данных

Когда функция запускается, она предоставляет моментальный снимок данных, связанных с событием. Вы можете использовать этот снимок для чтения или записи в документ, вызвавший событие, или использовать Firebase Admin SDK для доступа к другим частям вашей базы данных.

Данные события

Чтение данных

При запуске функции может потребоваться получить данные из документа, который был обновлен, или получить данные до обновления. Вы можете получить предыдущие данные, используя change.before.data() , который содержит снимок документа до обновления. Точно так же change.after.data() содержит состояние моментального снимка документа после обновления.

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();
    });

Вы можете получить доступ к свойствам, как и к любому другому объекту. Кроме того, вы можете использовать функцию 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');

Запись данных

Каждый вызов функции связан с определенным документом в вашей базе данных Cloud Firestore. Вы можете получить доступ к этому документу как DocumentReference в свойстве ref моментального снимка, возвращаемого вашей функцией.

Этот DocumentReference поступает из SDK Cloud Firestore Node.js и включает такие методы, как update() , set() и remove() , поэтому вы можете легко изменить документ, вызвавший функцию.

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});
    });

Данные вне триггерного события

Облачные функции выполняются в доверенной среде, что означает, что они авторизованы как учетная запись службы в вашем проекте. Вы можете выполнять чтение и запись с помощью 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({ ... });
  });

Ограничения

Обратите внимание на следующие ограничения для триггеров Cloud Firestore для облачных функций:

  • Заказ не гарантируется. Быстрые изменения могут инициировать вызовы функций в неожиданном порядке.
  • События доставляются по крайней мере один раз, но одно событие может привести к вызову нескольких функций. Избегайте зависимости от однократной механики и пишите идемпотентные функции .
  • Триггеры Cloud Firestore для Cloud Functions доступны только для Cloud Firestore в собственном режиме . Он недоступен для Cloud Firestore в режиме хранилища данных.