변경 내역으로 실시간 데이터 읽기
MongoDB 호환성을 갖춘 Firestore의 변경 내역을 사용하면 애플리케이션이 컬렉션 또는 전체 데이터베이스에 적용된 실시간 변경사항 (삽입, 업데이트, 삭제)에 액세스할 수 있습니다. 변경 스트림은 수정 시간별로 업데이트를 정렬합니다.
변경 스트림은 MongoDB 호환 API 및 기존 MongoDB 드라이버를 통해 액세스할 수 있습니다. MongoDB 호환성을 갖춘 Firestore의 변경 스트림 구현은 쓰기 및 읽기 병렬 처리에서 자동 파티셔닝의 고유한 구현을 통해 쓰기 및 읽기의 모든 처리량을 처리할 수 있습니다. 이를 통해 처리량이 높은 워크로드를 빌드할 수 있습니다. Firestore와 다른 스토리지 솔루션 간의 이전 및 데이터 동기화 인프라를 개선할 수도 있습니다.
MongoDB 드라이버와의 호환성 외에도 Firestore를 사용하여 변경 스트림을 병렬로 읽을 수 있습니다. 이를 통해 병렬의 높은 처리량 읽기 워크로드를 빌드할 수 있습니다. 각 스트림은 결과의 균등하게 분산된 파티션을 나타냅니다.
변경 스트림은 다음 기능을 지원합니다.
- 데이터베이스 또는 컬렉션 범위로 구성 가능한 변경 내역
- 생성 시 지정된 변경 내역의 보관 기간입니다. 기본 보관 기간은 7일이고 최소 보관 기간은 1일입니다. 보관 기간은 1일의 배수여야 하며 최대 7일입니다. 보존 기간은 생성 후 변경할 수 없습니다. 보관 기간을 변경하려면 변경 내역을 삭제하고 다시 만들어야 합니다.
db.collection.watch()및db.watch()를 사용하여 관찰할 수 있는delete,insert,update,drop변경 이벤트updateDescription.updatedFields에는 업데이트 차이가 포함되어 있습니다.- 모든
fullDocument및fullDocumentBeforeChange옵션- 업데이트를 위해 전체 문서를 조회하고 있습니다.
- 문서가 대체, 업데이트 또는 삭제되기 전의 사전 이미지입니다.
- 문서가 대체되거나 업데이트된 후의 이미지입니다.
- 1시간이 지난 사전 이미지와 사후 이미지를 사용하려면 point-in-time recovery (PITR)를 사용 설정해야 합니다.
resumeAfter및startAfter을 비롯한 모든 다시 시작 옵션watch()를 사용하여 변경사항을 관찰할 때$addFields,$match,$project,$replaceRoot,$replaceWith,$set,$unset과 같은 집계 단계를 연결할 수 있습니다.
변경 스트림 구성
데이터베이스의 기존 변경 스트림을 만들거나 삭제하거나 보려면Google Cloud 콘솔을 사용하세요.
역할 및 권한
변경 스트림을 만들고, 삭제하고, 나열하려면 주체에게 각각 datastore.schemas.create, datastore.schemas.delete, datastore.schemas.list Identity and Access Management (IAM) 권한이 필요합니다.
예를 들어 Datastore 색인 관리자 (roles/datastore.indexAdmin) 역할은 이러한 권한을 부여합니다.
변경 스트림 만들기
해당 변경 스트림 커서를 열려면 먼저 변경 스트림을 만들어야 합니다. 컬렉션 또는 데이터베이스 생성 시 자동 변경 스트림 사용 설정은 지원되지 않습니다.
변경 스트림을 만들려면 Google Cloud 콘솔을 사용하세요.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore Studio 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾아 작업 더보기를 클릭한 다음 변경 내역 만들기를 선택합니다.
- 고유한 변경 스트림 이름, 범위, 보관 기간을 입력한 다음 저장을 클릭합니다.
변경 스트림 보기
Google Cloud 콘솔에서 변경 내역에 관한 세부정보를 볼 수 있습니다.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore Studio 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾습니다.
- 노드를 열거나 닫으려면 노드 전환을 클릭합니다.
변경 스트림 삭제
변경 스트림을 삭제하려면 Google Cloud 콘솔을 사용하세요.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore Studio 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾습니다.
- 노드를 열거나 닫으려면 노드 전환을 클릭합니다.
- 탐색기에서 삭제하려는 변경 스트림을 찾습니다.
- 작업 더보기를 클릭한 다음 변경 스트림 삭제를 선택합니다.
- 대화상자에서 변경 스트림 이름을 입력하여 삭제를 확인한 다음 삭제를 클릭합니다.
변경 스트림 커서 열기 또는 재개
다음 예시에서는 변경 스트림 커서를 만들고, 재개하고, 구성하는 방법을 보여줍니다.
변경 스트림 커서를 만들기 전에 데이터베이스 또는 컬렉션에 대해 명시적으로 변경 스트림을 만들어야 합니다.
변경 스트림 커서 만들기
새 변경 스트림 커서를 만들려면 MongoDB 드라이버에서 watch 메서드를 사용하세요.
데이터베이스의 모든 변경사항을 수신 대기하려면 데이터베이스 범위 변경 스트림을 만들고 db 객체에서 watch 메서드를 호출합니다.
let cursor = db.watch()
컬렉션으로 범위가 지정된 커서를 만들려면 먼저 해당 컬렉션의 변경 스트림을 만들어야 합니다. 그런 다음 해당 컬렉션에서 watch 메서드를 호출합니다.
let cursor = db.my_collection.watch()
이제 변경 내역 커서를 만들었으므로 스트리밍을 시작할 수 있습니다.
예를 들어 문서를 삽입하고 커서에서 tryNext를 호출하면 변경사항이 변경 스트림에 표시됩니다.
let doc = db.my_collection.insertOne({value: "hello world"}) console.log(cursor.tryNext())
문서를 업데이트하고 삭제하면 변경사항이 변경 스트림에 표시됩니다.
db.my_collection.updateOne({"_id": doc.insertedId}, {$set: {value: "hello world!"}}) db.my_collection.deleteOne({"_id": doc.insertedId}}) // Prints the update event console.log(cursor.tryNext()) // Prints the delete event console.log(cursor.tryNext())
변경 스트림 재개
변경 스트림을 재개하려면 resumeAfter 또는 startAfter 옵션을 사용합니다.
변경 로그에서 resumeAfter 및 startAfter에서 재개할 위치를 확인하려면 재개 토큰을 사용하세요.
// Create a cursor and add one event to the change stream. let cursor = db.my_collection.watch(); db.my_collection.insertOne({value: "hello world"}); let event = cursor.tryNext(); // Get the resume token from the event. let resumeToken = event._id; // Add a new event to the change stream. db.my_collection.insertOne({value: "foobar"}); // Create a new cursor by using the resume token as a starting point. let newCursor = db.my_collection.watch({resumeAfter: resumeToken}) // Log the change event containing the "foobar" value. console.log(newCursor.tryNext())
startAfter를 사용합니다.
// Start after the resume token. let startAfterCursor = db.my_collection.watch({startAfter: resumeToken})
업데이트 및 삭제에 이전 이미지와 이후 이미지 포함
필요한 경우 업데이트 및 삭제 변경 이벤트에 문서의 이전 및 이후 이미지를 포함할 수 있습니다. 이미지 사용 가능 여부는 PITR (point-in-time recovery) 기간에 따라 달라지며, 1시간이 지난 문서 이미지를 읽으려면 PITR을 사용 설정해야 합니다.
변경 스트림은 PITR 기간을 활용하여 지정된 변경 이벤트 전후의 문서 보기를 제공합니다. 기본적으로 업데이트 이벤트에는 업데이트 작업으로 수정된 필드의 델타인 updateDescription 필드가 포함됩니다.
변경 이벤트에 사전 및 사후 이미지를 포함하려면 변경 스트림 쿼리에서 fullDocumentBeforeChange 및 fullDocument 옵션을 지정해야 합니다.
let cursor = db.my_collection.watch({ "fullDocument": "required", "fullDocumentBeforeChange": "required" })
쿼리가 PITR 보관 기간 외의 문서를 읽으려고 시도하거나 PITR이 사용 설정되지 않은 경우 required 값은 서버 측 오류 메시지를 표시합니다.
오류를 발생시키는 대신 이미지를 더 이상 사용할 수 없는 경우 whenAvailable 값을 사용하여 null 값을 반환할 수 있습니다.
let cursor = db.my_collection.watch({ "fullDocument": "whenAvailable", "fullDocumentBeforeChange": "whenAvailable" })
업데이트에 현재 이미지 포함
기본적으로 업데이트 이벤트에는 업데이트 작업으로 수정된 필드의 델타인 updateDescription 필드가 포함됩니다. 대신 전체 문서의 최신 버전을 조회하려면 fullDocument 옵션에서 updateLookup 값을 사용하세요.
이 기능은 PITR이 필요하지 않으며 문서에 대한 조회를 실행합니다.
let cursor = db.my_collection.watch({ "fullDocument": "updateLookup", })
병렬 읽기
처리량을 늘리려면 firestoreWorkerConfig 옵션을 사용하여 변경 스트림 쿼리를 여러 작업자에게 분할하면 됩니다. 각 작업자는 고유한 문서 집합의 변경사항을 제공합니다. runCommand 또는 aggregate 쿼리를 통해 병렬 커서를 만들어야 합니다.
예를 들어 다음과 같이 3개의 작업자에게 변경 내역을 분산할 수 있습니다.
let cursor1 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 0 }} }]); let cursor2 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 1 }} }]); let cursor3 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 2 }} }]);
변경 스트림 및 백업
백업 복원 작업에서는 변경 내역 구성과 변경 내역 데이터를 모두 사용할 수 없습니다. 변경 스트림이 있는 데이터베이스를 복원하는 경우 대상 데이터베이스에서 해당 변경 스트림을 다시 만들어 데이터베이스에 커서를 열어야 합니다.
결제
- 변경 스트림에는 읽기 단위 및 스토리지 비용이 발생합니다. 변경 스트림 가격 책정을 참고하세요.
- 읽기 요청 시간에 1시간이 지난 이전 및 이후 이미지를 포함하려면 PITR을 사용 설정해야 하며 이 경우 PITR 비용이 발생합니다.
동작 차이
다음 섹션에서는 MongoDB 호환성을 갖춘 Firestore와 MongoDB 간의 변경 스트림 차이점을 설명합니다.
updateDescription
updateDescription은 업데이트 작업으로 업데이트되거나 삭제된 필드를 설명하는 update 이벤트의 문서입니다. Firestore에서는 다음과 같은 차이점이 있습니다.
updateDescription에서truncatedArrays및disambiguatedPaths필드가 채워지지 않습니다.updateDescription.updatedFields는 변형이 적용되기 전후의 문서 이미지 간 표준 차이를 나타냅니다.
다음 문서의 초기 상태를 고려해 보세요.
db.my_collection.insertOne({ _id: 1, root: { array: [{a: 1}, {b: 2}, {c: 3}] } })
시나리오 1: 배열의 첫 번째 요소만 변경합니다.
이 시나리오에서는 Firestore 동작이 MongoDB와 일치합니다.
db.my_collection.updateOne( {_id: 1}, {'$set': {"root.array.0.a": 100}} ) { updatedFields: {"root.array.0.a": 100}, removedFields: [] }
시나리오 2: 전체 배열로 덮어쓰기
이 시나리오에서 작업은 첫 번째 배열 필드만 업데이트하지만 전체 배열을 덮어씁니다.
Firestore 업데이트 차이는 이러한 두 시나리오를 구분하지 않으며 두 시나리오 모두에 동일한 updateDescription.updatedFields를 반환합니다.
db.my_collection.updateOne( {_id: 1}, {'$set': {"root.array": [{a: 100}, {b: 2}, {c: 3}]}} ) // In other implementations, updatedFields reflects the mutation itself { updatedFields: { "root.array": [{a: 100}, {b: 2}, {c: 3}] }, removedFields: [] } // Firestore updatedFields is the diff between the before and after versions of the document { updatedFields: {"root.array.0.a": 100}, removedFields: [] }