С помощью Cloud Functions вы можете развернуть код для обработки событий, вызванных изменениями в базе данных Cloud Firestore, совместимой с MongoDB. Это позволяет добавлять серверную функциональность в приложение без необходимости запуска собственных серверов.
Cloud Functions (2-го поколения)
Cloud Functions for Firebase (2-го поколения), работающий на базе Cloud Run и Eventarc , предоставляет более мощную инфраструктуру, расширенный контроль над производительностью и масштабируемостью, а также более точный контроль над средой выполнения функций. Подробнее о Cloud Functions for Firebase (2-го поколения) см. в статье Cloud Functions for Firebase (2-го поколения) .
Cloud Firestore с функцией совместимости MongoDB
Пакет SDK Cloud Functions for Firebase экспортирует следующие триггеры событий совместимости Cloud Firestore с MongoDB, позволяя создавать обработчики, привязанные к определенным событиям совместимости Cloud Firestore с MongoDB:
Node.js
| Тип события | Курок |
|---|---|
onDocumentCreated | Срабатывает при первой записи в документ. |
onDocumentUpdated | Срабатывает, когда документ уже существует и в нем изменилось какое-либо значение. |
onDocumentDeleted | Срабатывает при удалении документа. |
onDocumentWritten | Срабатывает при срабатывании onDocumentCreated , onDocumentUpdated или onDocumentDeleted . |
onDocumentCreatedWithAuthContext | onDocumentCreated с дополнительной информацией об аутентификации |
onDocumentWrittenWithAuthContext | onDocumentWritten с дополнительной информацией об аутентификации |
onDocumentDeletedWithAuthContext | onDocumentDeleted с дополнительной информацией об аутентификации |
onDocumentUpdatedWithAuthContext | onDocumentUpdated с дополнительной информацией об аутентификации |
Питон
| Тип события | Курок |
|---|---|
on_document_created | Срабатывает при первой записи в документ. |
on_document_updated | Срабатывает, когда документ уже существует и в нем изменилось какое-либо значение. |
on_document_deleted | Срабатывает при удалении документа. |
on_document_written | Срабатывает при срабатывании on_document_created , on_document_updated или on_document_deleted . |
on_document_created_with_auth_context | on_document_created с дополнительной информацией об аутентификации |
on_document_updated_with_auth_context | on_document_updated с дополнительной информацией об аутентификации |
on_document_deleted_with_auth_context | on_document_deleted с дополнительной информацией об аутентификации |
on_document_written_with_auth_context | on_document_written с дополнительной информацией об аутентификации |
События совместимости Cloud Firestore с MongoDB срабатывают только при изменении документа. Обновление документа совместимости Cloud Firestore с MongoDB, данные в котором не изменялись (запись без операции), не генерирует событие обновления или записи. Невозможно добавлять события к определённым полям.
Если у вас еще нет проекта с поддержкой Cloud Functions for Firebase , прочтите статью Начало работы с Cloud Functions for Firebase (2-го поколения), чтобы настроить и оборудовать свой проект Cloud Functions for Firebase .
Написание Cloud Firestore с функциями, совместимыми с MongoDB
Определить триггер функции
Чтобы определить триггер совместимости Cloud Firestore с MongoDB, укажите путь к документу и тип события:
Node.js
const {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("my-collection/{docId}", (event) => {
/* ... */
});
Питон
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:
Пути к документам могут ссылаться либо на конкретный документ , либо на подстановочный шаблон .
Укажите один документ
Если вы хотите инициировать событие для любого изменения в определенном документе, то вы можете использовать следующую функцию.
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('firebase-functions/v2/firestore');
exports.myfunction = onDocumentWritten("users/marie", (event) => {
// Your code here
});
Питон
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:
Укажите группу документов с помощью подстановочных знаков
Если вы хотите прикрепить триггер к группе документов, например, к любому документу в определенной коллекции, то вместо идентификатора документа используйте {wildcard} :
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('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"}
});
Питон
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
В этом примере при изменении любого поля в документе users оно сопоставляется с подстановочным знаком userId .
Совпадения с подстановочными знаками извлекаются из пути к документу и сохраняются в event.params . Триггер всегда должен указывать на документ, даже если вы используете подстановочные знаки.
Триггеры событий
Запустить функцию при создании нового документа
Вы можете активировать функцию, которая будет срабатывать каждый раз при создании нового документа в коллекции. Этот пример функции срабатывает каждый раз при добавлении нового профиля пользователя:
Node.js
const {
onDocumentCreated,
Change,
FirestoreEvent
} = require('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 ...
});
Для получения дополнительной информации об аутентификации используйте onDocumentCreatedWithAuthContext .
Питон
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 ...
Запустить функцию при обновлении документа
Вы также можете активировать функцию, которая будет срабатывать при обновлении документа. В этом примере функция срабатывает, если пользователь меняет свой профиль:
Node.js
const {
onDocumentUpdated,
Change,
FirestoreEvent
} = require('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 ...
});
Для получения дополнительной информации об аутентификации используйте onDocumentUpdatedWithAuthContext .
Питон
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 ...
Запустить функцию при удалении документа
Вы также можете активировать функцию при удалении документа. Эта функция срабатывает, когда пользователь удаляет свой профиль:
Node.js
const {
onDocumentDeleted,
Change,
FirestoreEvent
} = require('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 ...
});
Для получения дополнительной информации об аутентификации используйте onDocumentDeletedWithAuthContext .
Питон
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 ...
Запустить функцию для всех изменений в документе
Если тип события не важен, вы можете отслеживать все изменения в документе, совместимом с Cloud Firestore и MongoDB, с помощью триггера события «Documentwritten». Этот пример функции срабатывает при создании, обновлении или удалении пользователя:
Node.js
const {
onDocumentWritten,
Change,
FirestoreEvent
} = require('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 ...
});
Для получения дополнительной информации об аутентификации используйте onDocumentWrittenWithAuthContext .
Питон
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 ...
Чтение и запись данных
При срабатывании функции создается снимок данных, связанных с событием. Вы можете использовать этот снимок для чтения или записи данных в документ, вызвавший событие, или использовать Firebase Admin SDK для доступа к другим частям базы данных.
Данные о событиях
Чтение данных
При срабатывании функции может потребоваться получить данные из документа, который был обновлён, или данные до обновления. Получить предыдущие данные можно с помощью event.data.before , который содержит снимок документа до обновления. Аналогично, event.data.after содержит снимок состояния документа после обновления.
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();
});
Питон
@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()
Вы можете получить доступ к свойствам так же, как к любому другому объекту. Кроме того, для доступа к определённым полям можно использовать функцию get :
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');
Питон
# 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"]
Запись данных
Каждый вызов функции связан с определённым документом в базе данных Cloud Firestore, совместимой с MongoDB. Вы можете получить доступ к этому документу в снимке, возвращаемом функцией.
Ссылка на документ включает такие методы, как update() , set() и remove() , чтобы вы могли изменить документ, вызвавший эту функцию.
Node.js
const {onDocumentUpdated} = require('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 event.data.after.ref.set({
name_change_count: count + 1
}, {merge: true});
});
Питон
@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})
Доступ к информации об аутентификации пользователя
При использовании одного из следующих типов событий вы можете получить доступ к информации об аутентификации пользователя, инициировавшего событие. Эта информация дополняет информацию, возвращаемую в базовом событии.
Node.js
-
onDocumentCreatedWithAuthContext -
onDocumentWrittenWithAuthContext -
onDocumentDeletedWithAuthContext -
onDocumentUpdatedWithAuthContext
Питон
-
on_document_created_with_auth_context -
on_document_updated_with_auth_context -
on_document_deleted_with_auth_context -
on_document_written_with_auth_context
Информацию о данных, доступных в контексте аутентификации, см. в разделе Контекст аутентификации . В следующем примере показано, как получить информацию об аутентификации:
Node.js
const {onDocumentWrittenWithAuthContext} = require('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});
});
Питон
@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
Данные за пределами события-триггера
Cloud Functions выполняются в доверенной среде. Они авторизованы как сервисная учётная запись в вашем проекте, и вы можете выполнять чтение и запись с помощью 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
});
});
Питон
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({
# ...
})
Ограничения
- Порядок не гарантируется. Быстрые изменения могут привести к вызову функций в неожиданном порядке.
- События доставляются как минимум один раз, но одно событие может привести к нескольким вызовам функций. Избегайте зависимости от механики «точно один раз» и пишите идемпотентные функции .
- Триггер связан с одной базой данных. Невозможно создать триггер, соответствующий нескольким базам данных.
- Удаление базы данных не приводит к автоматическому удалению всех триггеров в этой базе данных. Триггер перестаёт отправлять события, но продолжает существовать до тех пор, пока вы его не удалите .