Modificar dados com operações de pipeline
Use as etapas de linguagem de manipulação de dados (DML) update(...) e delete(...) para criar pipelines de dados que podem consultar documentos e, em seguida, excluir ou modificar dados.
Requisitos da versão
As operações descritas nesta página exigem a edição Enterprise do Firestore.
Antes de começar
Você precisa saber como consultar um banco de dados com operações de pipeline.
Atualizar documentos
Use o estágio de DML update(...) para criar pipelines de dados
que podem consultar documentos e adicionar ou modificar dados.
Todas as fases de DML precisam estar no final do pipeline.
Os documentos que entram nesse estágio precisam incluir o campo __name__ para
identificar quais documentos atualizar. A operação falhará se algum dos documentos que você tentar atualizar não existir.
Por exemplo,
a operação a seguir preenche uma alteração de modelo de dados em todos os documentos de um
grupo de coleções. O pipeline adiciona um campo preferences.color a todos os
documentos no grupo de coleções users que não têm esse campo.
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)
Excluir documentos
Use o estágio DML delete(...) para criar pipelines de dados
que podem consultar documentos e excluir dados.
Para evitar exclusões em massa acidentais, os pipelines que terminam em delete(...)
precisam incluir pelo menos um estágio where(...).
Todas as fases de DML precisam estar no final do pipeline.
Por exemplo, o pipeline a seguir exclui todos os documentos users com
address.users definido como USA e com __create_time__ menor que 10 dias:
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)
Modos de execução e consistência
As etapas de DML podem ser executadas dentro ou fora de uma transação explícita:
Execução transacional
A DML transacional oferece consistência atômica, do tipo "tudo ou nada", em todos os documentos e é compatível com todo o conjunto de estágios de consulta do pipeline. Isso o torna ideal para cargas de trabalho que exigem garantias de consistência estritas, em que atualizações parciais são inaceitáveis, ou que dependem de etapas de consulta complexas, desde que as modificações se encaixem nos limites de tamanho da transação.
Executar um pipeline de DML dentro de uma transação explícita (usando runTransaction /
transaction.execute(pipeline) ou a opção atomic: true) tem o seguinte
comportamento:
- Todas as mutações são confirmadas juntas ou revertidas completamente em caso de falha.
- Todos os estágios de consulta do pipeline são compatíveis antes de um estágio de DML (incluindo subconsultas
where,add_fields,union,find_nearesteaggregate). - Em uma transação, todas as operações de leitura precisam ser executadas antes das operações de gravação. Como um pipeline de DML realiza gravações, não é possível executar leituras
depois de executar um pipeline de DML na mesma transação. Por exemplo, não é possível
chamar um pipeline de DML várias vezes em uma única transação nem ler
documentos depois de executar um pipeline de DML. A tentativa de executar uma leitura após a execução de um pipeline de DML falha com um erro
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - A operação está sujeita aos limites de transação da edição Enterprise do Firestore.
Execução não transacional
A DML não transacional foi projetada para modificações em massa em um grande número de documentos sem que as limitações de tamanho da transação sejam atingidas. Ao bloquear no nível do documento, em vez de em toda a operação, ele permite que outras operações simultâneas continuem enquanto atualiza documentos em grande escala.
Quando as etapas de DML são executadas fora de uma transação explícita:
- Atualizações independentes e sucesso parcial: cada documento é atualizado de forma independente, e as operações não são atômicas entre os documentos. O pipeline é interrompido no primeiro erro, e os documentos modificados anteriormente permanecem gravados no banco de dados, o que permite um sucesso parcial.
- Suporte para preparo:
- Estágios avançados e de várias consultas (como
aggregate(...),distinct(...),unnest(...),find_nearest(...),union(...), mesclagens e subconsultas) não são compatíveis antes da DML fora de uma transação. Use uma transação se o pipeline exigir essas etapas.
- Estágios avançados e de várias consultas (como
- Limite de 20 pesquisas das regras de segurança: cada lote de documentos é executado na própria transação e reavalia as regras de segurança. Se as regras de segurança usarem
pesquisas
get()ouexists(), cada lote vai executar uma pesquisa, atingindo o limite de 20 pesquisas por solicitação depois de gravar aproximadamente 200 documentos e falhar comPERMISSION_DENIED. Use declarações personalizadas em vez de pesquisasget()ouexists()para evitar esse limite.
Limitações
Observe as seguintes limitações para as etapas de DML:
- Os estágios de DML precisam ser o último estágio em uma definição de pipeline antes de chamar
.execute(). - Quando executado fora de uma transação, cada documento é atualizado de forma independente, o que permite um sucesso parcial.
- As operações DML não transacionais sujeitas a regras de segurança com pesquisas
get()ouexists()são limitadas a aproximadamente 200 documentos devido ao limite de 20 pesquisas. - As operações DML transacionais são limitadas pelos limites de transação da edição Enterprise do Firestore. Como as transações do Firestore não permitem leituras após
a primeira gravação, não é possível chamar um pipeline de DML várias vezes em uma única
transação nem ler documentos após a execução de um pipeline de DML.
A tentativa de executar uma leitura após uma gravação de DML falha com um
erro
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - Se a etapa anterior à etapa de DML produzir vários documentos com o
mesmo
__name__ou for avaliada com o mesmo ID de documento de destino, cada mutação será processada sequencialmente:- Para
upsert(...)eupdate(...): várias mutações que visam o mesmo documento seguem a semântica "a última vence", em que a última mutação processada determina o estado final do documento. - Para
delete(...): a primeira tentativa exclui o documento, e as tentativas subsequentes para o mesmo documento são no-ops. - Para
insert(...): a primeira tentativa cria o documento, e as tentativas subsequentes que segmentam o mesmo ID de documento falham com um erroALREADY_EXISTS.
- Para