Google Firestore 연동
Google Firestore 컴포넌트는 Google Cloud Firestore Java library를 통해 Google Cloud Firestore에 접근할 수 있게 해 주는 컴포넌트예요. Camel 4.19부터 제공됐고, producer와 consumer를 모두 지원합니다. 실시간 리스너로 데이터를 동기화하고 오프라인 지원까지 갖춘 NoSQL 클라우드 데이터베이스에 라우트에서 바로 읽기·쓰기·쿼리할 수 있어요.
출처: 문서
본문
Camel 4.19부터 지원
producer와 consumer 모두 지원
Google Firestore 컴포넌트는 Google Cloud Firestore Java library를 통해 Google Cloud Firestore에 접근할 수 있게 해 줘요.
Firestore는 모바일, 웹, 서버 개발을 위한 유연하고 확장 가능한 NoSQL 클라우드 데이터베이스예요. 실시간 리스너로 클라이언트 앱 전반에 데이터를 동기화하고 오프라인 지원도 제공해요.
Maven 사용자는 이 컴포넌트를 쓰려면 pom.xml에 다음 의존성을 추가해야 해요.
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-google-firestore</artifactId>
<!-- use the same version as your Camel core version -->
<version>x.x.x</version>
</dependency>
인증 설정 (Authentication Configuration)
Google Firestore 컴포넌트 인증은 GCP 서비스 계정을 쓰는 상황을 대상으로 해요. 자세한 정보는 Google Firestore Quickstart를 참고하세요.
서비스 계정 키를 받았다면 애플리케이션 코드에 인증 자격 증명을 넘겨줄 수 있어요. Google 보안 자격 증명은 컴포넌트 엔드포인트를 통해 설정할 수 있습니다:
Java 전용: 엔드포인트 URI를 프로그래밍 방식으로 만들기
String endpoint = "google-firestore://myCollection?serviceAccountKey=/home/user/Downloads/my-key.json&projectId=my-project";
또는 GCP 자격 증명 파일 위치의 경로를 제공할 수도 있어요:
환경 변수 GOOGLE_APPLICATION_CREDENTIALS를 설정해 애플리케이션 코드에 인증 자격 증명을 넘겨줄 수도 있어요:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/my-key.json"
URI 형식 (URI Format)
google-firestore://collectionName?[options]
다음 형식으로 URI에 쿼리 옵션을 붙일 수 있어요: ?options=value&option2=value&…
예를 들어 users 컬렉션에서 문서 하나를 가져오려면 이렇게 해요:
from("direct:start")
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=getDocumentById&serviceAccountKey=/path/to/key.json&projectId=my-project")
.to("log:result");
<route>
<from uri="direct:start"/>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=getDocumentById&serviceAccountKey=/path/to/key.json&projectId=my-project"/>
<to uri="log:result"/>
</route>
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: getDocumentById
serviceAccountKey: /path/to/key.json
projectId: my-project
- to:
uri: log:result
옵션 설정 방법 (Configuring Options)
Camel 컴포넌트는 두 단계로 나눠 설정합니다:
-
컴포넌트(component) 레벨
-
엔드포인트(endpoint) 레벨
컴포넌트 옵션 설정 (Configuring Component Options)
컴포넌트 레벨에서는 엔드포인트들이 이어서 물려받는 일반적이고 공유되는 설정을 해요. 가장 상위의 설정 레벨이죠.
예를 들어 컴포넌트에는 보안 설정, 인증용 자격 증명, 네트워크 연결 URL 같은 것들이 있을 수 있어요.
컴포넌트에 따라 옵션이 몇 개뿐인 것도 있고 아주 많은 것도 있어요. 컴포넌트는 보통 널리 쓰이는 기본값이 미리 설정되어 있어서, 몇 가지 옵션만 설정하거나 아예 하나도 건드리지 않아도 되는 경우가 많아요.
컴포넌트는 다음 방법으로 설정할 수 있어요:
-
the Component DSL.
-
설정 파일(
application.properties,*.yaml파일 등). -
Java 코드에서 직접.
엔드포인트 옵션 설정 (Configuring Endpoint Options)
엔드포인트는 옵션이 많아서 설정에 시간을 더 쓰게 될 거예요. 이 옵션들이 엔드포인트가 원하는 일을 하도록 커스터마이즈해 줘요. 옵션은 엔드포인트가 consumer(from)로 쓰이는지, producer(to)로 쓰이는지, 둘 다인지에 따라 분류되기도 해요.
엔드포인트 설정은 대부분 엔드포인트 URI에 _path_와 query 파라미터로 바로 하는 경우가 많아요. Java에서 엔드포인트와 데이터 포맷을 _타입 세이프_하게 설정하려면 Endpoint DSL과 DataFormat DSL을 쓸 수도 있어요.
옵션을 설정할 때 좋은 습관은 Property Placeholders를 사용하는 거예요.
프로퍼티 플레이스홀더는 이런 장점이 있어요:
-
URL, 포트 번호, 민감한 정보 같은 설정을 하드코딩하는 걸 막아 줘요.
-
설정을 코드 밖으로 분리할 수 있어요.
-
코드가 더 유연해지고 재사용하기 좋아져요.
다음 두 섹션에서 모든 옵션을 나열해요. 먼저 컴포넌트 옵션, 그다음 엔드포인트 옵션 순서예요.
컴포넌트 옵션 (Component Options)
Google Firestore 컴포넌트가 지원하는 옵션은 아래와 같아요.
| Name | Description | Default | Type |
|---|---|---|---|
| configuration (common) | 컴포넌트 설정이에요. | GoogleFirestoreConfiguration | |
| databaseId (common) | Firestore 데이터베이스 ID예요. 지정하지 않으면 기본 데이터베이스 '(default)'를 사용해요. | String | |
| firestoreClient (common) | Autowired 연산에 사용할 Firestore 클라이언트예요. | Firestore | |
| projectId (common) | Google Cloud 프로젝트 ID예요. 지정하지 않으면 서비스 계정 키나 환경에서 알아내요. | String | |
| serviceAccountKey (common) | Firestore 클라이언트의 자격 증명으로 쓸 수 있는 서비스 계정 키예요. 기본으로 클래스패스에서 읽어 오지만, classpath:, file:, http: 접두어를 붙이면 다른 시스템에서 리소스를 읽어 올 수도 있어요. | String | |
| bridgeErrorHandler (consumer) | consumer를 Camel 라우팅 에러 핸들러로 브리징할 수 있게 해 줘요. 즉, Camel consumer가 들어오는 메시지를 가져오는 동안 발생한 예외(가능한 경우) 따위가 메시지로 처리돼 라우팅 에러 핸들러에서 다뤄져요. 중요: 서드파티 컴포넌트가 예외가 던져졌을 때 Camel에 알려 줄 수 있어야만 가능해요. 일부 컴포넌트는 이를 내부에서만 처리하기 때문에 bridgeErrorHandler를 쓸 수 없는 경우도 있어요. 그 외 상황에서는 향후 릴리스에서 서드파티 컴포넌트에 후킹해 이를 가능하게 만들도록 Camel 컴포넌트를 개선할 수도 있어요. 기본적으로 consumer는 org.apache.camel.spi.ExceptionHandler로 예외를 다루며, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | false | boolean |
| realtimeUpdates (consumer) | true면 consumer가 컬렉션의 실시간 업데이트를 리스닝해요. | false | boolean |
| maxPendingChanges (consumer (advanced)) | 두 폴 사이에서 버퍼링할 실시간 문서 변경의 최대 개수예요. 스냅샷 리스너가 보고한 변경은 다음 폴이 가져갈 때까지 버퍼에 쌓이므로, 컬렉션 변경 속도가 라우트의 소비 속도보다 빠르면 버퍼가 커져요. 버퍼가 가득 차면 가장 오래 묶어 둔 변경을 버리고 경고를 로그로 남겨요. 무한 버퍼를 쓰려면 0으로 설정하세요. realtimeUpdates가 켜져 있을 때만 사용돼요. | 0 | int |
| documentId (producer) | 문서 단위 연산에 사용할 문서 ID예요. | String | |
| lazyStartProducer (producer) | producer를 lazy(첫 메시지 시점)로 시작할지 여부예요. lazy 시작을 쓰면 producer가 시작 중 실패해서 라우트 시작이 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있고, 시작 실패 처리를 Camel의 라우팅 에러 핸들러로 넘길 수 있어요. 다만 첫 메시지를 처리하는 시점에 producer를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 유의하세요. | false | boolean |
| operation (producer) |
producer가 수행할 연산이에요.
Enum values:
-
setDocument
-
getDocumentById
-
updateDocument
-
deleteDocument
-
queryCollection
-
listDocuments
-
listCollections
-
createDocument
| | GoogleFirestoreOperations | | autowiredEnabled (advanced) | 오토와이어링 사용 여부예요. 레지스트리에서 일치하는 타입의 인스턴스가 하나만 있는지 찾아서 컴포넌트에 자동으로 설정하는(옵션이 autowired로 표시돼 있어야 함) 자동 오토와이어링에 쓰입니다. JDBC 데이터 소스, JMS 커넥션 팩토리, AWS 클라이언트 등을 자동 설정할 때 유용해요. | true | boolean | | healthCheckConsumerEnabled (health) | 이 컴포넌트의 consumer 기반 헬스 체크를 모두 켜고 끌 때 사용해요. | true | boolean | | healthCheckProducerEnabled (health) | 이 컴포넌트의 producer 기반 헬스 체크를 모두 켜고 끌 때 사용해요. 참고: Camel은 기본으로 producer 기반 헬스 체크를 모두 꺼 둬요. camel.health.producersEnabled=true로 설정하면 producer 체크를 전역으로 켤 수 있습니다. | true | boolean |
엔드포인트 옵션 (Endpoint Options)
Google Firestore 엔드포인트는 다음 URI 문법으로 설정해요:
google-firestore:collectionName
다음 _path_와 query 파라미터를 씁니다:
경로 파라미터 (Path Parameters)
| Name | Description | Default | Type |
|---|---|---|---|
| collectionName (common) | 필수 사용할 컬렉션 이름이에요. | String |
쿼리 파라미터 (Query Parameters)
| Name | Description | Default | Type |
|---|---|---|---|
| databaseId (common) | Firestore 데이터베이스 ID예요. 지정하지 않으면 기본 데이터베이스 '(default)'를 사용해요. | String | |
| firestoreClient (common) | Autowired 연산에 사용할 Firestore 클라이언트예요. | Firestore | |
| projectId (common) | Google Cloud 프로젝트 ID예요. 지정하지 않으면 서비스 계정 키나 환경에서 알아내요. | String | |
| serviceAccountKey (common) | Firestore 클라이언트의 자격 증명으로 쓸 수 있는 서비스 계정 키예요. 기본으로 클래스패스에서 읽어 오지만, classpath:, file:, http: 접두어를 붙이면 다른 시스템에서 리소스를 읽어 올 수도 있어요. | String | |
| realtimeUpdates (consumer) | true면 consumer가 컬렉션의 실시간 업데이트를 리스닝해요. | false | boolean |
| sendEmptyMessageWhenIdle (consumer) | 폴링 consumer가 아무 파일도 폴하지 못했을 때, 대신 빈 메시지(본문 없음)를 보내도록 이 옵션을 켤 수 있어요. | false | boolean |
| bridgeErrorHandler (consumer (advanced)) | consumer를 Camel 라우팅 에러 핸들러로 브리징할 수 있게 해 줘요. 즉, Camel consumer가 들어오는 메시지를 가져오는 동안 발생한 예외(가능한 경우) 따위가 메시지로 처리돼 라우팅 에러 핸들러에서 다뤄져요. 중요: 서드파티 컴포넌트가 예외가 던져졌을 때 Camel에 알려 줄 수 있어야만 가능해요. 일부 컴포넌트는 이를 내부에서만 처리하기 때문에 bridgeErrorHandler를 쓸 수 없는 경우도 있어요. 그 외 상황에서는 향후 릴리스에서 서드파티 컴포넌트에 후킹해 이를 가능하게 만들도록 Camel 컴포넌트를 개선할 수도 있어요. 기본적으로 consumer는 org.apache.camel.spi.ExceptionHandler로 예외를 다루며, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | false | boolean |
| exceptionHandler (consumer (advanced)) | consumer가 커스텀 ExceptionHandler를 쓰게 할 때 사용해요. bridgeErrorHandler 옵션이 켜져 있으면 이 옵션은 사용되지 않는다는 점에 유의하세요. 기본적으로 consumer는 예외를 직접 다루며, WARN 또는 ERROR 레벨로 로그를 남기고 무시해요. | ExceptionHandler | |
| exchangePattern (consumer (advanced)) |
consumer가 exchange를 만들 때의 exchange 패턴을 설정해요.
Enum values:
-
InOnly
-
InOut
| | ExchangePattern | | maxPendingChanges (consumer (advanced)) | 두 폴 사이에서 버퍼링할 실시간 문서 변경의 최대 개수예요. 스냅샷 리스너가 보고한 변경은 다음 폴이 가져갈 때까지 버퍼에 쌓이므로, 컬렉션 변경 속도가 라우트의 소비 속도보다 빠르면 버퍼가 커져요. 버퍼가 가득 차면 가장 오래 묶어 둔 변경을 버리고 경고를 로그로 남겨요. 무한 버퍼를 쓰려면 0으로 설정하세요. realtimeUpdates가 켜져 있을 때만 사용돼요. | 0 | int | | pollStrategy (consumer (advanced)) | Exchange가 만들어지고 Camel에서 라우팅되기 전, 폴 연산 중에 보통 발생하는 에러 처리를 제어할 수 있도록 커스텀 구현을 제공하게 해 주는 플러그 가능한 org.apache.camel.PollingConsumerPollingStrategy예요. | | PollingConsumerPollStrategy | | documentId (producer) | 문서 단위 연산에 사용할 문서 ID예요. | | String | | operation (producer) |
producer가 수행할 연산이에요.
Enum values:
-
setDocument
-
getDocumentById
-
updateDocument
-
deleteDocument
-
queryCollection
-
listDocuments
-
listCollections
-
createDocument
| | GoogleFirestoreOperations | | lazyStartProducer (producer (advanced)) | producer를 lazy(첫 메시지 시점)로 시작할지 여부예요. lazy 시작을 쓰면 producer가 시작 중 실패해서 라우트 시작이 실패하는 상황에서도 CamelContext와 라우트를 시작할 수 있고, 시작 실패 처리를 Camel의 라우팅 에러 핸들러로 넘길 수 있어요. 다만 첫 메시지를 처리하는 시점에 producer를 만들고 시작하는 데 시간이 조금 걸려서 전체 처리 시간이 길어질 수 있다는 점은 유의하세요. | false | boolean | | backoffErrorThreshold (scheduler) | backoffMultipler가 동작하기 전에 연속해서 발생해야 하는 에러 폴(오류로 실패한 폴) 횟수예요. | | int | | backoffIdleThreshold (scheduler) | backoffMultipler가 동작하기 전에 연속해서 발생해야 하는 유휴 폴 횟수예요. | | int | | backoffMultiplier (scheduler) | 연속된 유휴/에러 폴이 여러 번 이어졌을 때 예약 폴링 consumer가 백오프하게 해 줘요. multiplier는 다음 실제 시도가 다시 일어나기 전에 건너뛸 폴 횟수예요. 이 옵션을 쓸 때는 backoffIdleThreshold와/또는 backoffErrorThreshold도 함께 설정해야 해요. | | int | | delay (scheduler) | 다음 폴까지 기다리는 밀리초예요. | 500 | long | | greedy (scheduler) | greedy가 켜져 있으면, 이전 실행이 메시지를 1개 이상 폴했을 때 ScheduledPollConsumer가 바로 다시 실행돼요. | false | boolean | | initialDelay (scheduler) | 첫 폴이 시작되기 전까지의 밀리초예요. | 1000 | long | | repeatCount (scheduler) | 실행 횟수의 최대 한도를 지정해요. 1로 설정하면 스케줄러가 한 번만 실행되고, 5로 설정하면 다섯 번만 실행돼요. 0이나 음수는 계속 실행한다는 뜻이에요. | 0 | long | | runLoggingLevel (scheduler) |
consumer가 폴할 때 시작/완료 로그 한 줄을 남겨요. 이 옵션으로 그 로그의 레벨을 설정할 수 있어요.
Enum values:
-
TRACE
-
DEBUG
-
INFO
-
WARN
-
ERROR
-
OFF
| TRACE | LoggingLevel | | scheduledExecutorService (scheduler) | consumer가 사용할 커스텀/공유 스레드 풀을 설정하게 해 줘요. 기본으로 각 consumer는 자기만의 싱글 스레드 풀을 가져요. | | ScheduledExecutorService | | scheduler (scheduler) | camel-spring이나 camel-quartz 컴포넌트의 크론 스케줄러를 쓰게 해 줘요. 내장 스케줄러를 쓰려면 spring 또는 quartz 값을 사용하세요. | none | Object | | schedulerProperties (scheduler) | 커스텀 스케줄러나 Quartz, Spring 기반 스케줄러를 쓸 때 추가 프로퍼티를 설정하게 해 줘요. 접두어가 scheduler인 다중 값 옵션이에요. | | Map | | startScheduler (scheduler) | 스케줄러를 자동으로 시작할지 여부예요. | true | boolean | | timeUnit (scheduler) |
initialDelay와 delay 옵션의 시간 단위예요.
Enum values:
-
NANOSECONDS
-
MICROSECONDS
-
MILLISECONDS
-
SECONDS
-
MINUTES
-
HOURS
-
DAYS
| MILLISECONDS | TimeUnit | | useFixedDelay (scheduler) | 고정 지연(fixed delay)을 쓸지 고정 레이트(fixed rate)를 쓸지 제어해요. 자세한 내용은 JDK의 ScheduledExecutorService를 참고하세요. | true | boolean |
메시지 헤더 (Message Headers)
Google Firestore 컴포넌트는 다음 메시지 헤더를 지원해요:
| Name | Description | Default | Type |
|---|---|---|---|
CamelGoogleFirestoreOperation (producer) Constant: OPERATION |
수행할 연산이에요.
Enum values:
-
setDocument
-
getDocumentById
-
updateDocument
-
deleteDocument
-
queryCollection
-
listDocuments
-
listCollections
-
createDocument
| | GoogleFirestoreOperations |
| CamelGoogleFirestoreCollectionName (producer) Constant: COLLECTION_NAME | 연산에 사용할 컬렉션 이름이에요. | | String |
| CamelGoogleFirestoreDocumentId (producer) Constant: DOCUMENT_ID | 연산에 사용할 문서 ID예요. | | String |
| CamelGoogleFirestoreQueryField (producer) Constant: QUERY_FIELD | 쿼리 필터링에 쓸 필드 이름이에요. | | String |
| CamelGoogleFirestoreQueryOperator (producer) Constant: QUERY_OPERATOR | 쿼리 필터링에 쓸 연산자예요 (예: ==, , =, !=, array-contains, in, array-contains-any, not-in). | | String |
| CamelGoogleFirestoreQueryValue (producer) Constant: QUERY_VALUE | 쿼리 필터링에 쓸 값이에요. | | Object |
| CamelGoogleFirestoreQueryLimit (producer) Constant: QUERY_LIMIT | 쿼리에서 반환할 문서의 최대 개수예요. | | Integer |
| CamelGoogleFirestoreQueryOrderBy (producer) Constant: QUERY_ORDER_BY | 쿼리 결과를 정렬할 기준 필드예요. | | String |
| CamelGoogleFirestoreQueryOrderDirection (producer) Constant: QUERY_ORDER_DIRECTION |
쿼리 결과의 정렬 방향이에요 (ASCENDING 또는 DESCENDING).
Enum values:
-
ASCENDING
-
DESCENDING
| | Query$Direction |
| CamelGoogleFirestoreResponseDocumentId (consumer) Constant: RESPONSE_DOCUMENT_ID | 응답에서 나온 문서 ID예요. | | String |
| CamelGoogleFirestoreResponseDocumentPath (consumer) Constant: RESPONSE_DOCUMENT_PATH | 응답에서 나온 문서 경로예요. | | String |
| CamelGoogleFirestoreResponseCreateTime (consumer) Constant: RESPONSE_CREATE_TIME | 문서 생성 시각이에요. | | Timestamp |
| CamelGoogleFirestoreResponseUpdateTime (consumer) Constant: RESPONSE_UPDATE_TIME | 문서 업데이트 시각이에요. | | Timestamp |
| CamelGoogleFirestoreResponseReadTime (consumer) Constant: RESPONSE_READ_TIME | 문서 읽기 시각이에요. | | Timestamp |
| CamelGoogleFirestoreChangeType (consumer) Constant: CHANGE_TYPE | 실시간 리스너가 보고한 변경 유형이에요: ADDED, MODIFIED 또는 REMOVED. realtimeUpdates가 켜져 있을 때만 설정돼요. | | String |
| CamelGoogleFirestoreMerge (producer) Constant: MERGE | true면 문서를 덮어쓰는 대신 기존 문서 데이터와 병합해요. | false | Boolean |
| CamelGoogleFirestoreMergeFields (producer) Constant: MERGE_FIELDS | merge 옵션을 쓸 때 병합할 필드 경로 목록이에요. | | List |
사용법 (Usage)
Google Firestore producer 연산 (Google Firestore Producer Operations)
Google Firestore 컴포넌트는 producer 쪽에서 다음 연산을 제공해요:
-
setDocument- 지정한 ID로 문서를 새로 만들거나 덮어써요. -
createDocument- 자동 생성된 ID로 새 문서를 만들어요. -
getDocumentById- ID로 문서를 조회해요. -
updateDocument- 문서의 특정 필드를 업데이트해요. -
deleteDocument- 문서를 삭제해요. -
queryCollection- 필터로 문서를 쿼리해요. -
listDocuments- 컬렉션의 모든 문서를 나열해요. -
listCollections- 모든 컬렉션을 나열해요.
연산을 명시적으로 지정하지 않으면 producer가 setDocument 연산을 수행해요.
지원 입력 포맷 (Supported Input Formats)
문서 데이터가 필요한 연산(setDocument, createDocument, updateDocument)에는 컴포넌트가 다음 입력 포맷을 받아들여요:
-
Map<String, Object> - 필드 이름을 키로 갖는 Java Map
-
JSON String - 유효한 JSON 객체 문자열 (예:
{"name": "John", "age": 30}) -
Any object - Camel의 타입 컨버터로 Map으로 변환할 수 있는 객체
JSON 문자열 예시:
from("direct:start")
.setBody(constant("{\"name\":\"John Doe\",\"email\":\"john@example.com\",\"age\":30,\"active\":true}"))
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=setDocument");
<route>
<from uri="direct:start"/>
<setBody>
<constant>{"name":"John Doe","email":"john@example.com","age":30,"active":true}</constant>
</setBody>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=setDocument"/>
</route>
- route:
from:
uri: direct:start
steps:
- setBody:
constant: '{"name":"John Doe","email":"john@example.com","age":30,"active":true}'
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: setDocument
Google Firestore consumer (Google Firestore Consumer)
consumer는 컬렉션에서 문서를 폴링하거나 실시간 업데이트를 리스닝할 수 있어요.
-
폴링 모드 (기본값): 컬렉션의 모든 문서를 주기적으로 폴링해요
-
실시간 모드: Firestore의 실시간 리스너로 문서 변경을 리스닝해요
실시간 업데이트를 켜려면:
from("google-firestore://myCollection?realtimeUpdates=true")
.to("log:changes");
<route>
<from uri="google-firestore://myCollection?realtimeUpdates=true"/>
<to uri="log:changes"/>
</route>
- route:
from:
uri: google-firestore://myCollection
parameters:
realtimeUpdates: true
steps:
- to:
uri: log:changes
실시간 모드에서는 리스너가 보고한 문서 변경이 다음 폴이 가져갈 때까지 버퍼에 쌓여요. 이 버퍼는 기본적으로 무제한이라, 컬렉션 변경 속도가 라우트의 소비 속도보다 빠르면 버퍼가 계속 커지고 라우트가 일시 중단된 동안에도 자라나요. maxPendingChanges로 상한을 두면 버퍼가 가득 찼을 때 가장 오래 묶어 둔 변경을 버리고 경고를 로그로 남겨서, 라우트가 컬렉션의 가장 최근 상태를 유지하게 돼요.
from("google-firestore://myCollection?realtimeUpdates=true&maxPendingChanges=1000")
.to("log:changes");
고급 컴포넌트 설정 (Advanced Component Configuration)
Firestore 클라이언트 인스턴스 설정을 더 세밀하게 제어해야 한다면, 인스턴스를 직접 만들고 Camel google-firestore 컴포넌트 설정에서 참조할 수 있어요:
from("google-firestore://myCollection?firestoreClient=#myFirestoreClient")
.to("mock:result");
<route>
<from uri="google-firestore://myCollection?firestoreClient=#myFirestoreClient"/>
<to uri="mock:result"/>
</route>
- route:
from:
uri: google-firestore://myCollection
parameters:
firestoreClient: "#myFirestoreClient"
steps:
- to:
uri: mock:result
producer 연산 예제 (Producer Operation Examples)
자동 생성 ID로 문서 만들기 (Create Document with Auto-Generated ID)
이 연산은 자동 생성된 고유 ID로 새 문서를 만들어요:
from("direct:start")
.setBody(constant("{\"name\":\"John Doe\",\"email\":\"john@example.com\",\"age\":30}"))
.to("google-firestore://users?operation=createDocument")
.log("Created document with ID: ${header.CamelGoogleFirestoreResponseDocumentId}");
<route>
<from uri="direct:start"/>
<setBody>
<constant>{"name":"John Doe","email":"john@example.com","age":30}</constant>
</setBody>
<to uri="google-firestore://users?operation=createDocument"/>
<log message="Created document with ID: ${header.CamelGoogleFirestoreResponseDocumentId}"/>
</route>
- route:
from:
uri: direct:start
steps:
- setBody:
constant: '{"name":"John Doe","email":"john@example.com","age":30}'
- to:
uri: google-firestore://users
parameters:
operation: createDocument
- log:
message: "Created document with ID: ${header.CamelGoogleFirestoreResponseDocumentId}"
지정한 ID로 문서 설정 (Set Document with Specific ID)
이 연산은 지정한 ID로 문서를 새로 만들거나 덮어써요:
from("direct:start")
.setBody(constant("{\"name\":\"Jane Doe\",\"email\":\"jane@example.com\"}"))
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=setDocument")
.log("Document saved");
<route>
<from uri="direct:start"/>
<setBody>
<constant>{"name":"Jane Doe","email":"jane@example.com"}</constant>
</setBody>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=setDocument"/>
<log message="Document saved"/>
</route>
- route:
from:
uri: direct:start
steps:
- setBody:
constant: '{"name":"Jane Doe","email":"jane@example.com"}'
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: setDocument
- log:
message: "Document saved"
병합(merge)으로 문서 설정 (Set Document with Merge)
문서를 덮어쓰는 대신 기존 문서 데이터와 병합하려면:
from("direct:start")
.setBody(constant("{\"lastLogin\":\"2025-01-15T10:30:00Z\"}"))
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.setHeader("CamelGoogleFirestoreMerge", constant(true))
.to("google-firestore://users?operation=setDocument")
.log("Document merged");
<route>
<from uri="direct:start"/>
<setBody>
<constant>{"lastLogin":"2025-01-15T10:30:00Z"}</constant>
</setBody>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<setHeader name="CamelGoogleFirestoreMerge">
<constant>true</constant>
</setHeader>
<to uri="google-firestore://users?operation=setDocument"/>
<log message="Document merged"/>
</route>
- route:
from:
uri: direct:start
steps:
- setBody:
constant: '{"lastLogin":"2025-01-15T10:30:00Z"}'
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- setHeader:
name: CamelGoogleFirestoreMerge
constant: true
- to:
uri: google-firestore://users
parameters:
operation: setDocument
- log:
message: "Document merged"
ID로 문서 조회 (Get Document by ID)
이 연산은 ID로 문서를 조회해요:
from("direct:start")
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=getDocumentById")
.log("Document data: ${body}");
<route>
<from uri="direct:start"/>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=getDocumentById"/>
<log message="Document data: ${body}"/>
</route>
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: getDocumentById
- log:
message: "Document data: ${body}"
응답 본문에는 문서 데이터를 담은 Map<String, Object>가 담기고, 문서가 존재하지 않으면 null이 돼요.
문서 업데이트 (Update Document)
이 연산은 문서 전체를 덮어쓰지 않고 특정 필드만 업데이트해요:
from("direct:start")
.setBody(constant("{\"status\":\"active\",\"updatedAt\":\"2025-01-15T10:30:00Z\"}"))
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=updateDocument")
.log("Document updated");
<route>
<from uri="direct:start"/>
<setBody>
<constant>{"status":"active","updatedAt":"2025-01-15T10:30:00Z"}</constant>
</setBody>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=updateDocument"/>
<log message="Document updated"/>
</route>
- route:
from:
uri: direct:start
steps:
- setBody:
constant: '{"status":"active","updatedAt":"2025-01-15T10:30:00Z"}'
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: updateDocument
- log:
message: "Document updated"
문서 삭제 (Delete Document)
이 연산은 문서를 삭제해요:
from("direct:start")
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=deleteDocument")
.log("Document deleted: ${body}");
<route>
<from uri="direct:start"/>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=deleteDocument"/>
<log message="Document deleted: ${body}"/>
</route>
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: deleteDocument
- log:
message: "Document deleted: ${body}"
문서 목록 조회 (List Documents)
이 연산은 컬렉션의 모든 문서를 나열해요:
from("direct:start")
.to("google-firestore://users?operation=listDocuments")
.log("Found ${body.size()} documents");
<route>
<from uri="direct:start"/>
<to uri="google-firestore://users?operation=listDocuments"/>
<log message="Found ${body.size()} documents"/>
</route>
- route:
from:
uri: direct:start
steps:
- to:
uri: google-firestore://users
parameters:
operation: listDocuments
- log: "Found ${body.size()} documents"
응답 본문에는 각 문서의 데이터를 담은 List<Map<String, Object>>가 담겨요. 각 문서에는 문서 ID와 경로가 담긴 _id, _path 필드가 들어 있어요.
컬렉션 쿼리 (Query Collection)
이 연산은 필터로 문서를 쿼리해요:
from("direct:start")
.setHeader("CamelGoogleFirestoreQueryField", constant("age"))
.setHeader("CamelGoogleFirestoreQueryOperator", constant(">="))
.setHeader("CamelGoogleFirestoreQueryValue", constant(21))
.setHeader("CamelGoogleFirestoreQueryLimit", constant(10))
.setHeader("CamelGoogleFirestoreQueryOrderBy", constant("age"))
.to("google-firestore://users?operation=queryCollection")
.log("Found ${body.size()} matching documents");
<route>
<from uri="direct:start"/>
<setHeader name="CamelGoogleFirestoreQueryField">
<constant>age</constant>
</setHeader>
<setHeader name="CamelGoogleFirestoreQueryOperator">
<constant>>=</constant>
</setHeader>
<setHeader name="CamelGoogleFirestoreQueryValue">
<constant>21</constant>
</setHeader>
<setHeader name="CamelGoogleFirestoreQueryLimit">
<constant>10</constant>
</setHeader>
<setHeader name="CamelGoogleFirestoreQueryOrderBy">
<constant>age</constant>
</setHeader>
<to uri="google-firestore://users?operation=queryCollection"/>
<log message="Found ${body.size()} matching documents"/>
</route>
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelGoogleFirestoreQueryField
constant: age
- setHeader:
name: CamelGoogleFirestoreQueryOperator
constant: ">="
- setHeader:
name: CamelGoogleFirestoreQueryValue
constant: "21"
- setHeader:
name: CamelGoogleFirestoreQueryLimit
constant: "10"
- setHeader:
name: CamelGoogleFirestoreQueryOrderBy
constant: age
- to:
uri: google-firestore://users
parameters:
operation: queryCollection
- log:
message: "Found ${body.size()} matching documents"
지원되는 쿼리 연산자:
-
==oreq- 같음 -
!=orne- 같지 않음 -
<orlt- 작음 -
⇐orlte- 작거나 같음 -
>orgt- 큼 -
>=orgte- 크거나 같음 -
array-contains- 배열이 값을 포함 -
in- 값이 목록에 포함 -
array-contains-any- 배열이 목록의 값 중 하나라도 포함 -
not-in- 값이 목록에 포함되지 않음
컬렉션 목록 조회 (List Collections)
이 연산은 데이터베이스의 모든 컬렉션을 나열해요:
from("direct:start")
.to("google-firestore://anyCollection?operation=listCollections")
.log("Collections: ${body}");
<route>
<from uri="direct:start"/>
<to uri="google-firestore://anyCollection?operation=listCollections"/>
<log message="Collections: ${body}"/>
</route>
- route:
from:
uri: direct:start
steps:
- to:
uri: google-firestore://anyCollection
parameters:
operation: listCollections
- log: "Collections: ${body}"
특정 문서 아래의 하위 컬렉션을 나열하려면:
from("direct:start")
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=listCollections")
.log("Subcollections: ${body}");
<route>
<from uri="direct:start"/>
<setHeader name="CamelGoogleFirestoreDocumentId">
<constant>user123</constant>
</setHeader>
<to uri="google-firestore://users?operation=listCollections"/>
<log message="Subcollections: ${body}"/>
</route>
- route:
from:
uri: direct:start
steps:
- setHeader:
name: CamelGoogleFirestoreDocumentId
constant: user123
- to:
uri: google-firestore://users
parameters:
operation: listCollections
- log:
message: "Subcollections: ${body}"
consumer 예제 (Consumer Examples)
문서 폴링 (Poll Documents)
컬렉션의 모든 문서를 30초마다 폴링해요:
from("google-firestore://users?delay=30000")
.log("Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}")
.log("Document data: ${body}")
.to("mock:result");
<route>
<from uri="google-firestore://users?delay=30000"/>
<log message="Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}"/>
<log message="Document data: ${body}"/>
<to uri="mock:result"/>
</route>
- route:
from:
uri: google-firestore://users
parameters:
delay: 30000
steps:
- log: "Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}"
- log: "Document data: ${body}"
- to:
uri: mock:result
실시간 업데이트 (Real-time Updates)
문서 변경을 실시간으로 리스닝해요:
from("google-firestore://users?realtimeUpdates=true")
.log("Change type: ${header.CamelGoogleFirestoreChangeType}")
.log("Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}")
.log("Document data: ${body}")
.to("mock:result");
<route>
<from uri="google-firestore://users?realtimeUpdates=true"/>
<log message="Change type: ${header.CamelGoogleFirestoreChangeType}"/>
<log message="Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}"/>
<log message="Document data: ${body}"/>
<to uri="mock:result"/>
</route>
- route:
from:
uri: google-firestore://users
parameters:
realtimeUpdates: true
steps:
- log: "Change type: ${header.CamelGoogleFirestoreChangeType}"
- log: "Document ID: ${header.CamelGoogleFirestoreResponseDocumentId}"
- log: "Document data: ${body}"
- to:
uri: mock:result
CamelGoogleFirestoreChangeType 헤더는 변경 유형이 ADDED, MODIFIED, REMOVED 중 무엇인지 알려 줘요.
데이터 타입 (Data Types)
입력 데이터 포맷 (Input Data Formats)
쓰기 연산(setDocument, createDocument, updateDocument)에는 컴포넌트가 메시지 본문에서 다음 입력 포맷을 받아들여요:
| Format | Description | Example |
|---|---|---|
Map<String, Object> |
필드 이름을 키로 갖는 Java Map | Map.of("name", "John", "age", 30) |
| JSON String | 유효한 JSON 객체 문자열 | {"name": "John", "age": 30} |
| POJO | Camel의 타입 컨버터로 Map으로 변환할 수 있는 객체 | Custom Java beans |
JSON 문자열 입력 (JSON String Input)
JSON 문자열을 메시지 본문에 곧바로 담아 보낼 수 있어요. 컴포넌트가 자동으로 파싱해 줘요:
Java 전용: 텍스트 블록으로 JSON 문자열 입력하기
// Simple JSON
from("direct:start")
.setBody(constant("{\"name\": \"John\", \"age\": 30}"))
.setHeader("CamelGoogleFirestoreDocumentId", constant("user123"))
.to("google-firestore://users?operation=setDocument");
// Multi-line JSON with text blocks (Java 15+)
String json = """
{
"name": "John Doe",
"email": "john@example.com",
"age": 30,
"active": true,
"tags": ["admin", "user"],
"address": {
"street": "123 Main St",
"city": "New York",
"zip": "10001"
}
}
""";
from("direct:start")
.setBody(constant(json))
.to("google-firestore://users?operation=createDocument");
파일에서 JSON 읽기 (Reading JSON from Files)
from("file:data/users?noop=true&include=.*\\.json")
.setHeader("CamelGoogleFirestoreDocumentId", simple("${file:name.noext}"))
.to("google-firestore://users?operation=setDocument")
.log("Imported: ${file:name}");
<route>
<from uri="file:data/users?noop=true&include=.*\.json"/>
<setHeader name="CamelGoogleFirestoreDocumentId">
<simple>${file:name.noext}</simple>
</setHeader>
<to uri="google-firestore://users?operation=setDocument"/>
<log message="Imported: ${file:name}"/>
</route>
- route:
from:
uri: file:data/users
parameters:
noop: true
include: ".*\\.json"
steps:
- setHeader:
name: CamelGoogleFirestoreDocumentId
simple: "${file:name.noext}"
- to:
uri: google-firestore://users
parameters:
operation: setDocument
- log:
message: "Imported: ${file:name}"
REST API 연동 (REST API Integration)
from("rest:post:/api/users")
.to("google-firestore://users?operation=createDocument")
.setBody(simple("{\"id\": \"${header.CamelGoogleFirestoreResponseDocumentId}\"}"));
<route>
<from uri="rest:post:/api/users"/>
<to uri="google-firestore://users?operation=createDocument"/>
<setBody>
<simple>{"id": "${header.CamelGoogleFirestoreResponseDocumentId}"}</simple>
</setBody>
</route>
- route:
from:
uri: rest:post:/api/users
steps:
- to:
uri: google-firestore://users
parameters:
operation: createDocument
- setBody:
simple: '{"id": "${header.CamelGoogleFirestoreResponseDocumentId}"}'
지원되는 Firestore 데이터 타입 (Supported Firestore Data Types)
다음 Java 타입은 Firestore 데이터 타입으로 자동 변환돼요:
| Java Type | Firestore Type | Notes |
|---|---|---|
String |
String | 텍스트 데이터 |
Integer, Long |
Integer | 64비트 부호 있는 정수 |
Double, Float |
Floating-point | 64비트 배정밀도 |
Boolean |
Boolean | true 또는 false |
Date, java.sql.Timestamp |
Timestamp | Firestore Timestamp로 변환 |
com.google.cloud.Timestamp |
Timestamp | 네이티브 Firestore Timestamp |
List<?> |
Array | 순서 있는 목록, 중첩 타입 지원 |
Map<String, ?> |
Map | 중첩 문서/객체 |
null |
Null | null 값 |
byte[] |
Bytes | 바이너리 데이터 (최대 1MB) |
com.google.cloud.firestore.GeoPoint |
GeoPoint | 위도/경도 좌표 |
com.google.cloud.firestore.DocumentReference |
Reference | 다른 문서에 대한 참조 |
출력 데이터 포맷 (Output Data Formats)
단일 문서 연산 (Single Document Operations)
getDocumentById의 응답 본문은 다음과 같아요:
-
Map<String, Object>- 문서가 있으면 문서 데이터 -
null- 문서가 존재하지 않으면
목록/쿼리 연산 (List/Query Operations)
listDocuments와 queryCollection의 응답 본문은 다음과 같아요:
List<Map<String, Object>>- 문서 목록
각 문서 Map에는 추가 메타데이터 필드가 들어 있어요:
-
_id- 문서 ID -
_path- 전체 문서 경로 (예:users/user123)
삭제 연산 (Delete Operation)
deleteDocument의 응답 본문은 다음과 같아요:
Boolean- 항상true(Firestore 삭제는 멱등[idempotent]해요)
컬렉션 목록 연산 (List Collections Operation)
listCollections의 응답 본문은 다음과 같아요:
List<String>- 컬렉션 ID 목록
에러 처리 (Error Handling)
입력 본문을 Map으로 변환할 수 없으면(예: 잘못된 JSON) InvalidPayloadException이 던져져요:
org.apache.camel.InvalidPayloadException: No body available of type: java.util.Map
...Caused by: Unexpected character ('x' (code 120)): was expecting...
메시지 헤더 (Message Headers)
컴포넌트는 다음 헤더를 사용해요:
producer 헤더 (Producer Headers (Input))
| Header | Type | Description |
|---|---|---|
CamelGoogleFirestoreOperation |
GoogleFirestoreOperations |
수행할 연산 |
CamelGoogleFirestoreCollectionName |
String |
컬렉션 이름을 오버라이드해요 |
CamelGoogleFirestoreDocumentId |
String |
문서 연산에 쓸 문서 ID |
CamelGoogleFirestoreQueryField |
String |
쿼리 필터링에 쓸 필드 이름 |
CamelGoogleFirestoreQueryOperator |
String |
쿼리 필터링에 쓸 연산자 |
CamelGoogleFirestoreQueryValue |
Object |
쿼리 필터링에 쓸 값 |
CamelGoogleFirestoreQueryLimit |
Integer |
반환할 문서의 최대 개수 |
CamelGoogleFirestoreQueryOrderBy |
String |
결과 정렬 기준 필드 |
CamelGoogleFirestoreQueryOrderDirection |
Query.Direction |
정렬 방향 (ASCENDING/DESCENDING) |
CamelGoogleFirestoreMerge |
Boolean |
기존 문서와 데이터 병합 |
CamelGoogleFirestoreMergeFields |
List<String> |
병합할 특정 필드 |
consumer/응답 헤더 (Consumer/Response Headers (Output))
| Header | Type | Description |
|---|---|---|
CamelGoogleFirestoreResponseDocumentId |
String |
문서 ID |
CamelGoogleFirestoreResponseDocumentPath |
String |
전체 문서 경로 |
CamelGoogleFirestoreResponseCreateTime |
Timestamp |
문서 생성 시각 |
CamelGoogleFirestoreResponseUpdateTime |
Timestamp |
문서 마지막 업데이트 시각 |
CamelGoogleFirestoreResponseReadTime |
Timestamp |
문서 읽기 시각 |
CamelGoogleFirestoreChangeType |
String |
실시간 업데이트의 변경 유형 (ADDED, MODIFIED, REMOVED) |
더 알아보기 (Learn more)
Google Firestore의 인증과 서비스 계정 설정은 Google Firestore Quickstart에서, Firestore 데이터 모델과 실시간 리스너는 Google Cloud Firestore 문서에서 더 깊이 살펴볼 수 있어요. 실제 동작은 위의 producer 연산 예제와 consumer 예제 섹션의 라우트 예시를 그대로 따라 해 보는 게 가장 빠르고, 의존성은 문서 앞부분의 Maven 좌표(org.apache.camel:camel-google-firestore) 그대로 추가하면 됩니다. 다른 Camel 컴포넌트 문서는 Camel 컴포넌트 목록에서 찾아볼 수 있어요.