Cloud Functions를 사용하면
Firebase Realtime Database: 클라이언트 코드를 업데이트할 필요가 없습니다.
Cloud Functions를 사용하면 전체 관리 기능으로 Realtime Database 작업을 실행할 수 있습니다.
Realtime Database에 대한 각 변경사항이 처리되도록 합니다.
각 단계마다 다릅니다 DataSnapshot
또는 Admin SDK를 통해 Firebase Realtime Database를 변경할 수 있습니다.
일반적인 수명 주기에서 Firebase Realtime Database 함수는 다음을 실행합니다.
- 특정 Realtime Database 위치가 변경되기를 기다립니다.
- 이벤트가 발생할 때 트리거되어 작업을 수행합니다. 어떻게 해야 하나요? Cloud Functions인가요? 사용 사례를 참조하세요.
- 지정된 문서에 저장된 데이터의 스냅샷이 포함된 데이터 객체를 수신합니다.
Realtime Database 함수 트리거
Realtime Database 이벤트의 새 함수 만들기
(functions.database
) 받는사람
함수가 트리거되는 시점을 제어하고, 이벤트 핸들러 중 하나를 지정합니다.
이벤트를 리슨할 Realtime Database 경로를 지정합니다.
이벤트 핸들러 설정
함수를 사용하면 두 가지 수준의 특이도로 Realtime Database 이벤트를 처리할 수 있습니다. 특히 생성, 업데이트, 또는 삭제 이벤트를 수신 대기하거나 경로에 대한 모든 유형의 변경사항을 수신 대기할 수 있습니다. Cloud Functions는 Realtime Database에 다음 이벤트 핸들러를 지원합니다.
onWrite()
- Realtime Database에서 데이터가 생성, 업데이트 또는 삭제될 때 트리거됩니다.onCreate()
- Realtime Database에 새 데이터가 생성될 때 트리거됩니다.onUpdate()
- Realtime Database에서 데이터가 업데이트될 때 트리거됩니다 .onDelete()
- 데이터가 Realtime Database에서 삭제될 때 트리거됩니다 .
인스턴스 및 경로 지정
함수가 트리거되는 시점과 위치를 제어하려면 ref(path)
를 호출하여 경로를 지정하고 필요하다면 instance('INSTANCE_NAME')
로 Realtime Database 인스턴스를 지정합니다. 그렇지 않은 경우
인스턴스를 지정하면 함수가 다음 인스턴스의 기본 Realtime Database 인스턴스에 배포됩니다.
Firebase 프로젝트 예시:
- 기본 Realtime Database 인스턴스:
functions.database.ref('/foo/bar')
- 이름이 'my-app-db-2'인 인스턴스:
functions.database.instance('my-app-db-2').ref('/foo/bar')
이러한 메서드는 함수가 내부의 특정 경로에서 쓰기를 처리하도록 지시합니다.
Realtime Database 인스턴스 경로를 지정하면 경로와 터치하는 모든 쓰기와 일치하게 됩니다.
쓰기 권한,
발생할 수 있습니다. 경로를 설정하는 경우
함수를 /foo/bar
로 사용하면 다음 두 위치 모두의 이벤트와 일치합니다.
/foo/bar
/foo/bar/baz/really/deep/path
두 경우 모두 /foo/bar
에서 이벤트가 발생한 것으로 해석되고, 이벤트 데이터에 /foo/bar
의 이전 데이터와 새 데이터가 포함됩니다. 이벤트 데이터가 큰 경우에는 데이터베이스 루트 근처에 단일 함수를 사용하는 대신 더 깊은 경로에 여러 함수를 사용하는 것이 좋습니다. 성능을 최적화하려면 최대한 깊은 수준의 데이터만 요청합니다.
경로 구성요소를 중괄호로 묶어 와일드 카드로 지정할 수 있습니다. ref('foo/{bar}')
는 /foo
의 모든 하위 경로와 매칭됩니다. 함수의 EventContext.params
객체에서 이 와일드 카드 경로 구성요소의 값을 확인할 수 있습니다. 이 예시에서는 값이 context.params.bar
로 제공됩니다.
와일드 카드가 포함된 경로는 단일 쓰기 작업의 여러 이벤트와 일치할 수 있습니다. 다음을 삽입하면
{
"foo": {
"hello": "world",
"firebase": "functions"
}
}
"hello": "world"
와 "firebase": "functions"
에 대해 각각 한 번씩 "/foo/{bar}"
경로와 두 번 일치하게 됩니다.
이벤트 데이터 처리
Realtime Database 이벤트 처리 시 반환되는 데이터 객체는
DataSnapshot
onWrite
또는 onUpdate
이벤트의 경우
첫 번째 매개변수는 스냅샷 2개가 포함된 Change
객체입니다.
데이터의 상태를 나타내는
이벤트를 발생시킵니다. onCreate
및 onDelete
이벤트의 경우
반환되는 데이터 객체는 생성하거나 삭제한 데이터의 스냅샷입니다.
이 예시에서 함수는 지정된 경로의 스냅샷을 가져와 해당 위치의 문자열을 대문자로 변환하고 수정된 문자열을 데이터베이스에 씁니다.
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
사용자 인증 정보 액세스
EventContext.auth
및 EventContext.authType
에서 권한을 포함하여 함수를 트리거한 사용자의 정보에 액세스할 수 있습니다. 이 방법을 사용하면 사용자의 권한 수준에 따라 함수에서 다른 작업을 완료할 수 있으므로 보안 규칙을 적용하는 데 유용합니다.
const functions = require('firebase-functions/v1');
const admin = require('firebase-admin');
exports.simpleDbFunction = functions.database.ref('/path')
.onCreate((snap, context) => {
if (context.authType === 'ADMIN') {
// do something
} else if (context.authType === 'USER') {
console.log(snap.val(), 'written by', context.auth.uid);
}
});
또한 사용자 인증 정보를 활용하여 사용자로 '가장'하고 사용자 대신 쓰기 작업을 수행할 수 있습니다. 동시 실행 문제를 방지하기 위해 아래에 나와 있는 것처럼 앱 인스턴스를 삭제해야 합니다.
exports.impersonateMakeUpperCase = functions.database.ref('/messages/{pushId}/original')
.onCreate((snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const app = admin.initializeApp(appOptions, 'app');
const uppercase = snap.val().toUpperCase();
const ref = snap.ref.parent.child('uppercase');
const deleteApp = () => app.delete().catch(() => null);
return app.database().ref(ref).set(uppercase).then(res => {
// Deleting the app is necessary for preventing concurrency leaks
return deleteApp().then(() => res);
}).catch(err => {
return deleteApp().then(() => Promise.reject(err));
});
});
이전 값 읽기
Change
객체의 before
속성을 사용하면 이벤트가 발생하기 전에 Realtime Database에 저장된 데이터를 검사할 수 있습니다. before
속성은 DataSnapshot
을 반환합니다. 여기서 모든
메서드 (예:
val()
및
exists()
)
이전 값을 참조하세요 다시 새 값을 읽으려면 원본 DataSnapshot
을 사용하거나 after
속성을 읽으면 됩니다. Change
의 이 속성은 다음을 나타내는 또 다른 DataSnapshot
입니다.
이벤트가 발생한 후의 데이터 상태입니다.
예를 들어 before
속성을 사용하여 데이터를 처음 만들 때만 함수가 텍스트를 대문자로 변환하도록 할 수 있습니다.
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return change.after.ref.parent.child('uppercase').set(uppercase);
});