Cloud Functions를 사용하면 코드를 배포하여 트리거된 이벤트를 처리할 수 있습니다. Cloud Firestore 데이터베이스의 변경사항으로 인한 변경 덕분에 자체 서버를 실행하지 않고도 앱에 서버 측 기능을 쉽게 추가할 수 있습니다.
Cloud Functions (2세대)
제공: Cloud Run 및 Eventarc, Cloud Functions for Firebase (2세대)은 더 강력한 성능을 제공합니다. 인프라, 성능 및 확장성에 대한 고급 제어 등 함수 런타임을 제어할 수 있습니다 2세대에 관한 자세한 내용은 Firebase용 Cloud Functions (2세대) 자세히 알아보기 자세한 내용은 Cloud Functions로 Cloud Firestore를 확장합니다.
함수 트리거 Cloud Firestore개
Cloud Functions for Firebase SDK는 다음 Cloud Firestore를 내보냅니다. 특정 Cloud Firestore에 연결된 핸들러를 만들 수 있는 이벤트 트리거 이벤트:
Node.js
이벤트 유형 | 트리거 |
---|---|
onDocumentCreated |
문서를 처음으로 기록할 때 트리거됩니다. |
onDocumentUpdated |
이미 존재하는 문서에서 값이 변경되었을 때 트리거됩니다. |
onDocumentDeleted |
문서가 삭제될 때 트리거됩니다. |
onDocumentWritten |
onDocumentCreated , onDocumentUpdated 또는 onDocumentDeleted 가 트리거될 때 트리거됩니다. |
onDocumentCreatedWithAuthContext |
추가 인증 정보가 포함된 onDocumentCreated |
onDocumentWrittenWithAuthContext |
추가 인증 정보가 포함된 onDocumentWritten |
onDocumentDeletedWithAuthContext |
추가 인증 정보가 포함된 onDocumentDeleted |
onDocumentUpdatedWithAuthContext |
추가 인증 정보가 포함된 onDocumentUpdated |
Python(미리보기)
이벤트 유형 | 트리거 |
---|---|
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 이벤트 트리거만 확인할 수 있습니다 데이터가 사용되는 Cloud Firestore 문서 업데이트 변경되지 않는 경우(노옵스(no-ops) 쓰기)는 업데이트 또는 쓰기 이벤트를 생성하지 않습니다. 특정 필드에 이벤트를 추가할 수 없습니다.
Cloud Functions for Firebase에 사용 설정된 프로젝트가 아직 없는 경우 다음을 참조하세요. Cloud Functions for Firebase (2세대) 시작하기 Cloud Functions for Firebase 프로젝트를 구성하고 설정합니다.
Cloud Firestore 트리거 함수 작성
함수 트리거 정의
Cloud Firestore 트리거를 정의하려면 문서 경로와 이벤트 유형을 지정합니다.
Node.js
import {
onDocumentWritten,
onDocumentCreated,
onDocumentUpdated,
onDocumentDeleted,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("my-collection/{docId}", (event) => {
/* ... */
});
Python(미리보기)
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
import {
onDocumentWritten,
Change,
FirestoreEvent
} from "firebase-functions/v2/firestore";
exports.myfunction = onDocumentWritten("users/marie", (event) => {
// Your code here
});
Python(미리보기)
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:
와일드 카드를 사용한 문서 그룹 지정
특정 컬렉션의 문서 등 한 문서 그룹에 트리거를 연결하려면 문서 ID 대신 {wildcard}
를 사용하면 됩니다.
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(미리보기)
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
라는 와일드 카드와 일치시킵니다.
users
의 문서에 하위 컬렉션이 있고, 이 하위 컬렉션 문서 중 하나에서 필드가 변경되면 userId
와일드 카드가 트리거되지 않습니다.
와일드 카드 일치는 문서 경로에서 추출되어 event.params
에 저장됩니다.
개수 제한 없이 원하는 만큼 와일드 카드를 정의하여 명시적인 컬렉션 또는 문서 ID를 대체할 수 있습니다. 예를 들면 다음과 같습니다.
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(미리보기)
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"}
와일드 카드를 사용할 때도 트리거는 항상 문서를 가리켜야 합니다.
예를 들어 {messageCollectionId}
는 컬렉션이므로 users/{userId}/{messageCollectionId}
는 유효하지 않습니다. 그러나 {messageId}
가 항상 문서를 가리키므로 users/{userId}/{messageCollectionId}/{messageId}
는 유효합니다.
이벤트 트리거
새 문서가 생성될 때 함수 트리거
컬렉션에 새 문서가 생성될 때마다 함수를 트리거할 수 있습니다. 다음은 새 사용자 프로필이 추가될 때마다 트리거되는 함수의 예시입니다.
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 ...
});
추가 인증 정보는 onDocumentCreatedWithAuthContext
를 사용합니다.
Python(미리보기)
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
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 ...
});
추가 인증 정보는 onDocumentUpdatedWithAuthContext
를 사용합니다.
Python(미리보기)
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
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 ...
});
추가 인증 정보는 onDocumentDeletedWithAuthContext
를 사용합니다.
Python(미리보기)
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 문서의 변경사항 이벤트 있습니다. 다음은 사용자가 생성, 업데이트 또는 삭제될 때 실행되는 함수의 예시입니다.
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 ...
});
추가 인증 정보는 onDocumentWrittenWithAuthContext
를 사용합니다.
Python(미리보기)
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();
});
Python(미리보기)
@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');
Python(미리보기)
# 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 데이터베이스 함수로 반환되는 스냅샷에서 해당 문서에 액세스할 수 있습니다.
문서 참조에는 update()
, set()
, remove()
와 같은 메서드가 포함되므로 함수를 트리거한 문서를 수정할 수 있습니다.
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(미리보기)
@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
Python(미리보기)
on_document_created_with_auth_context
on_document_updated_with_auth_context
on_document_deleted_with_auth_context
on_document_written_with_auth_context
인증 컨텍스트에서 사용할 수 있는 데이터에 대한 자세한 내용은 다음을 참조하세요. Auth Context(인증 컨텍스트). 다음 예시에서는 인증 정보를 검색하는 방법을 보여줍니다.
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(미리보기)
@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
});
});
Python(미리보기)
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({
# ...
})
제한사항
Cloud Functions의 Cloud Firestore 트리거에 대한 다음 제한사항에 유의하세요.
- Cloud Functions (1세대) 기본 요건은 기존 '(기본값)'입니다. 데이터베이스를 생성할 수 있습니다 그렇지 않습니다. Cloud Firestore라는 데이터베이스 또는 Datastore 모드를 지원합니다. Cloud Functions를 사용하세요. (2세대)를 사용하여 이러한 경우에 이벤트를 구성합니다.
- 순서는 보장되지 않습니다. 급격하게 변경하면 예기치 않은 순서로 함수 호출이 트리거될 수 있습니다.
- 이벤트는 최소 1회 전송되지만 하나의 이벤트에 함수가 여러 번 호출될 수 있습니다. 정확히 한 번에 처리하는 메커니즘에 의존하지 말고 멱등 함수를 작성하세요.
- Datastore 모드의 Cloud Firestore Cloud Functions (2세대)이 필요합니다. Cloud Functions (1세대)는 Datastore 모드를 지원합니다
- 트리거는 단일 데이터베이스와 연결됩니다. 여러 데이터베이스와 일치하는 트리거를 만들 수 없습니다.
- 데이터베이스를 삭제해도 해당 데이터베이스의 트리거가 자동으로 삭제되지 않습니다. 트리거가 이벤트 제공을 중지하지만 트리거를 삭제하기 전까지 계속 존재합니다.
- 일치하는 이벤트가 최대 요청 크기를 초과하는 경우
이벤트가 Cloud Functions (1세대)로 전달되지 않을 수 있습니다.
- 요청 크기로 인해 전송되지 않은 이벤트는 플랫폼 로그에 로깅되고 프로젝트의 로그 사용량에 반영됩니다.
- 이러한 로그는 로그 탐색기에서 '크기가 1세대... 한도를 초과하여 Cloud 함수에 이벤트를 전송할 수 없음'이라는
error
심각도의 메시지와 함께 확인할 수 있습니다.functionName
필드 아래에서 함수 이름을 찾을 수 있습니다.receiveTimestamp
필드가 지금부터 1시간 이내인 경우 타임스탬프 전후의 스냅샷과 함께 해당 문서를 읽어 실제 이벤트 콘텐츠를 추론할 수 있습니다. - 이러한 주기를 피하려면 다음을 수행하면 됩니다.
- Cloud Functions (2세대)로 이전 및 업그레이드
- 문서 크기 줄이기
- 문제의 Cloud Functions 삭제
- 제외를 사용하여 로깅 자체를 사용 중지할 수 있지만 그래도 문제가 되는 이벤트가 전송되지 않습니다.