파이프라인 작업으로 데이터 수정
update(...) 및 delete(...) 데이터 조작 언어 (DML) 단계를 사용하여 문서를 쿼리한 후 데이터를 삭제하거나 수정할 수 있는 데이터 파이프라인을 구성합니다.
버전 요구사항
이 페이지에 설명된 작업에는 Firestore Enterprise 버전이 필요합니다.
시작하기 전에
파이프라인 작업으로 데이터베이스를 쿼리하는 방법을 숙지해야 합니다.
문서 업데이트
update(...) DML 단계를 사용하여 문서를 쿼리한 후 데이터를 추가하거나 수정할 수 있는 데이터 파이프라인을 구성합니다.
모든 DML 단계는 파이프라인 끝에 있어야 합니다.
이 단계로 들어오는 문서에는 업데이트할 문서를 식별하기 위해 __name__ 필드가 포함되어야 합니다. 업데이트하려는 문서가 존재하지 않으면 작업이 실패합니다.
예를 들어 다음 작업은 컬렉션 그룹의 모든 문서에 데이터 모델 변경사항을 백필합니다. 파이프라인은 users 컬렉션 그룹에서 해당 필드가 누락된 모든 문서에 preferences.color 필드를 추가합니다.
Node.js
const snapshot = await db.pipeline() .collectionGroup("users") .where(not(exists(field("preferences.color")))) .addFields(constant(null).as("preferences.color")) .removeFields("color") .update() .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Constant, Field, Not snapshot = ( client.pipeline() .collection_group("users") .where(Not(Field.of("preferences.color").exists())) .add_fields(Constant.of(None).as_("preferences.color")) .remove_fields("color") .update() .execute() )
Java
Pipeline.Snapshot snapshot = firestore.pipeline() .collectionGroup("users") .where(not(exists(field("preferences.color")))) .addFields(constant((String) null).as("preferences.color")) .removeFields("color") .update() .execute().get();
Go
snapshot := client.Pipeline(). CollectionGroup("users"). Where(firestore.Not(firestore.FieldExists(firestore.FieldOf("preferences.color")))). AddFields(firestore.Selectables( firestore.ConstantOfNull().As("preferences.color"), )). RemoveFields(firestore.Fields("color")). Update(). Execute(ctx)
문서 삭제
delete(...) DML 단계를 사용하여 문서를 쿼리한 후 데이터를 삭제할 수 있는 데이터 파이프라인을 구성합니다.
실수로 일괄 삭제되는 것을 방지하려면 delete(...)로 끝나는 파이프라인에 where(...) 단계를 하나 이상 포함해야 합니다.
모든 DML 단계는 파이프라인 끝에 있어야 합니다.
예를 들어 다음 파이프라인은 address.users가 USA로 설정되고 __create_time__가 10일 미만인 모든 users 문서를 삭제합니다.
Node.js
const pipeline = db.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").timestampAdd("day", 10).lessThan(currentTimestamp())) .delete(); await pipeline.execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import CurrentTimestamp, Field snapshot = ( client.pipeline() .collection_group("users") .where(Field.of("address.country").equal("USA")) .where( Field.of("__create_time__") .timestamp_add("day", 10) .less_than(CurrentTimestamp()) ) .delete() .execute() )
Java
Pipeline.Snapshot deleteResults = firestore.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").add(constant(10)).lessThan(currentTimestamp())) .delete() .execute().get();
Go
snapshot := client.Pipeline(). CollectionGroup("users"). Where(firestore.FieldOf("address.country").Equal("USA")). Where(firestore.FieldOf("__create_time__").Add(firestore.ConstantOf(10)).LessThan(firestore.CurrentTimestamp())). Delete(). Execute(ctx)
실행 모드 및 일관성
DML 단계는 명시적 트랜잭션 내부 또는 트랜잭션 외부에서 실행할 수 있습니다.
트랜잭션 실행
트랜잭션 DML은 문서 전반에 걸쳐 원자적이고 전부 아니면 전무인 일관성을 제공하며 전체 파이프라인 쿼리 단계를 지원합니다. 따라서 수정사항이 트랜잭션 크기 한도 내에 맞는 경우 부분 업데이트가 허용되지 않는 엄격한 일관성 보장이 필요하거나 복잡한 쿼리 단계에 의존하는 워크로드에 적합합니다.
명시적 트랜잭션 내에서 DML 파이프라인을 실행하면 (runTransaction/transaction.execute(pipeline) 또는 atomic: true 옵션 사용) 다음과 같이 작동합니다.
- 모든 변형은 함께 커밋되거나 실패 시 완전히 롤백됩니다.
- 모든 파이프라인 쿼리 단계는 DML 단계 (
where,add_fields,union,find_nearest,aggregate하위 쿼리 포함) 전에 지원됩니다. - 트랜잭션에서 모든 읽기 작업은 쓰기 작업 전에 실행되어야 합니다. DML 파이프라인은 쓰기를 수행하므로 동일한 트랜잭션에서 DML 파이프라인을 실행한 후에는 읽기를 실행할 수 없습니다. 예를 들어 단일 트랜잭션에서 DML 파이프라인을 여러 번 호출할 수 없으며 DML 파이프라인을 실행한 후 문서를 읽을 수 없습니다. DML 파이프라인 실행 후 읽기를 실행하려고 하면
FAILED_PRECONDITION오류와 함께 실패합니다.Cannot have reads after the first write in a Firestore transaction. - 이 작업에는 Firestore Enterprise 버전 트랜잭션 한도가 적용됩니다.
비트랜잭션 실행
비트랜잭션 DML은 트랜잭션 크기 제한에 도달하지 않고도 많은 수의 문서에서 일괄 수정을 수행할 수 있도록 설계되었습니다. 전체 작업이 아닌 문서 수준에서 잠그면 대규모로 문서를 업데이트하는 동안 다른 동시 작업을 진행할 수 있습니다.
명시적 트랜잭션 외부에서 DML 단계가 실행되는 경우:
- 독립적인 업데이트 및 부분 성공: 각 문서는 서로 독립적으로 업데이트되며 작업은 문서 간에 원자적이지 않습니다. 파이프라인은 첫 번째 오류에서 중지되고 이전에 수정된 문서는 데이터베이스에 기록된 상태로 유지되므로 부분적인 성공이 발생할 수 있습니다.
- 스테이지 지원:
- 고급 및 다중 쿼리 단계 (예:
aggregate(...),distinct(...),unnest(...),find_nearest(...),union(...), 조인, 하위 쿼리)는 트랜잭션 외부의 DML 전에 지원되지 않습니다. 파이프라인에 이러한 단계가 필요한 경우 트랜잭션을 사용합니다.
- 고급 및 다중 쿼리 단계 (예:
- 보안 규칙 20회 조회 한도: 각 문서 배치는 자체 트랜잭션에서 실행되고 보안 규칙을 다시 평가합니다. 보안 규칙에서
get()또는exists()조회를 사용하는 경우 각 배치가 조회를 실행하여 약 200개의 문서를 작성한 후 요청당 조회 한도인 20회에 도달하고PERMISSION_DENIED로 인해 실패합니다. 이 한도를 방지하려면get()또는exists()조회 대신 커스텀 클레임을 사용하세요.
제한사항
DML 단계에는 다음과 같은 제한사항이 있습니다.
- DML 단계는
.execute()를 호출하기 전에 파이프라인 정의의 마지막 단계여야 합니다. - 트랜잭션 외부에서 실행하면 각 문서가 서로 독립적으로 업데이트되며 부분적으로 성공할 수 있습니다.
get()또는exists()조회가 있는 보안 규칙이 적용되는 비트랜잭션 DML 작업은 20개 조회 한도로 인해 약 200개 문서로 제한됩니다.- 트랜잭션 DML 작업은 Firestore Enterprise 버전 트랜잭션 한도로 제한됩니다. Firestore 트랜잭션은 첫 번째 쓰기 후 읽기를 허용하지 않으므로 단일 트랜잭션 내에서 DML 파이프라인을 여러 번 호출할 수 없으며 DML 파이프라인을 실행한 후 문서를 읽을 수 없습니다.
DML 쓰기 후 읽기를 실행하려고 하면
FAILED_PRECONDITION오류와 함께 실패합니다.Cannot have reads after the first write in a Firestore transaction. - DML 단계 이전 단계에서 동일한
__name__를 가진 여러 문서를 생성하거나 동일한 대상 문서 ID로 평가되는 경우 각 변형은 순차적으로 처리됩니다.upsert(...)및update(...): 동일한 문서를 대상으로 하는 여러 변형은 '마지막 변형이 적용됨' 의미 체계를 따르며, 마지막으로 처리된 변형이 문서의 최종 상태를 결정합니다.delete(...): 첫 번째 시도에서 문서를 삭제하고 동일한 문서에 대한 후속 시도는 수행되지 않습니다.insert(...): 첫 번째 시도에서 문서를 만들고 동일한 문서 ID를 타겟팅하는 후속 시도는ALREADY_EXISTS오류와 함께 실패합니다.