Użyj etapów języka manipulacji danymi (DML) update(...) i delete(...), aby utworzyć potoki danych, które mogą wysyłać zapytania o dokumenty, a następnie usuwać lub modyfikować dane.
Wymagania dotyczące wersji
Operacje opisane na tej stronie wymagają wersji Firestore Enterprise.
Zanim zaczniesz
Musisz wiedzieć, jak wysyłać zapytania do bazy danych za pomocą operacji potoku.
Aktualizowanie dokumentów
Użyj etapu DML update(...), aby utworzyć potoki danych, które mogą wysyłać zapytania o dokumenty, a następnie dodawać lub modyfikować dane.
Wszystkie etapy DML muszą znajdować się na końcu potoku.
Dokumenty, które trafiają na ten etap, muszą zawierać pole __name__, aby można było określić, które dokumenty należy zaktualizować. Operacja się nie powiedzie, jeśli którykolwiek z dokumentów, które próbujesz zaktualizować, nie istnieje.
Na przykład ta operacja uzupełnia zmianę modelu danych we wszystkich dokumentach w grupie kolekcji. Potok dodaje pole preferences.color do wszystkich dokumentów w grupie kolekcji users, w których brakuje tego pola.
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)
Usuń dokumenty
Użyj etapu DML delete(...), aby utworzyć potoki danych, które mogą wysyłać zapytania o dokumenty, a następnie usuwać dane.
Aby zapobiec przypadkowemu usuwaniu zbiorczemu, potoki kończące się na delete(...) powinny zawierać co najmniej 1 etap where(...).
Wszystkie etapy DML muszą znajdować się na końcu potoku.
Na przykład ten potok usuwa wszystkie dokumenty users, w których pole address.users ma wartość USA, a pole __create_time__ ma wartość mniejszą niż 10 dni:
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)
Tryby wykonywania i spójność
Etapy DML można wykonywać w ramach transakcji jawnej lub poza transakcją:
Wykonywanie transakcyjne
Transakcyjny język DML zapewnia niepodzielną spójność typu „wszystko albo nic” w dokumentach i obsługuje pełny zestaw etapów zapytań potoku. Dzięki temu idealnie nadaje się do zbiorów zadań, które wymagają ścisłych gwarancji spójności, gdzie częściowe aktualizacje są niedopuszczalne, lub które opierają się na złożonych etapach zapytania, pod warunkiem że modyfikacje mieszczą się w limitach rozmiaru transakcji.
Uruchomienie potoku DML w ramach jawnej transakcji (za pomocą runTransaction / transaction.execute(pipeline) lub opcji atomic: true) powoduje następujące zachowanie:
- Wszystkie mutacje są zatwierdzane razem lub całkowicie wycofywane w przypadku niepowodzenia.
- Przed etapem DML obsługiwane są wszystkie etapy zapytania potoku (w tym podzapytania
where,add_fields,union,find_nearestiaggregate). - W transakcji wszystkie operacje odczytu muszą zostać wykonane przed operacjami zapisu. Potok DML wykonuje operacje zapisu, więc po uruchomieniu potoku DML nie można wykonywać operacji odczytu w tej samej transakcji. Nie możesz na przykład wywołać potoku DML wielokrotnie w ramach jednej transakcji ani odczytać dokumentów po wykonaniu potoku DML. Próba wykonania odczytu po nieudanym uruchomieniu potoku DML kończy się błędem
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - Operacja podlega limitom transakcji w wersji Firestore Enterprise.
Wykonanie nietransakcyjne
Nietransakcyjny język DML jest przeznaczony do zbiorczych modyfikacji dużej liczby dokumentów bez przekraczania limitów rozmiaru transakcji. Dzięki blokowaniu na poziomie dokumentu, a nie całej operacji, inne równoczesne operacje mogą być wykonywane podczas aktualizowania dokumentów na dużą skalę.
Gdy etapy DML są wykonywane poza jawną transakcją:
- Niezależne aktualizacje i częściowe powodzenie: każdy dokument jest aktualizowany niezależnie od innych, a operacje nie są niepodzielne w różnych dokumentach. Potok zatrzymuje się przy pierwszym błędzie, a wcześniej zmodyfikowane dokumenty pozostają zapisane w bazie danych, co pozwala na częściowe powodzenie.
- Pomoc na etapie:
- Zaawansowane i wielozapytaniowe etapy (takie jak
aggregate(...),distinct(...),unnest(...),find_nearest(...),union(...), złączenia i podzapytania) nie są obsługiwane przed DML poza transakcją. Jeśli Twój potok wymaga tych etapów, użyj transakcji.
- Zaawansowane i wielozapytaniowe etapy (takie jak
- Limit 20 wyszukiwań w regułach zabezpieczeń: każda partia dokumentów jest wykonywana we własnej transakcji i ponownie ocenia reguły zabezpieczeń. Jeśli Twoje reguły zabezpieczeń używają wyszukiwania
get()lubexists(), każda grupa wykonuje wyszukiwanie, osiągając limit 20 wyszukiwań na żądanie po zapisaniu około 200 dokumentów i kończąc się błędemPERMISSION_DENIED. Aby uniknąć tego limitu, zamiast wyszukiwańget()lubexists()używaj twierdzeń niestandardowych.
Ograniczenia
Pamiętaj o tych ograniczeniach dotyczących etapów DML:
- Etapy DML muszą być ostatnim etapem w definicji potoku przed wywołaniem
.execute(). - Gdy operacja jest wykonywana poza transakcją, każdy dokument jest aktualizowany niezależnie od innych, co umożliwia częściowe powodzenie.
- Nietransakcyjne operacje DML podlegające regułom zabezpieczeń z wyszukiwaniami
get()lubexists()są ograniczone do około 200 dokumentów ze względu na limit 20 wyszukiwań. - Transakcyjne operacje DML są ograniczone przez limity transakcji Firestore Enterprise. Transakcje Firestore nie zezwalają na odczyty po pierwszym zapisie, dlatego nie można wielokrotnie wywoływać potoku DML w ramach jednej transakcji ani odczytywać dokumentów po wykonaniu potoku DML.
Próba wykonania odczytu po nieudanym zapisie DML kończy się błędem
FAILED_PRECONDITION:Cannot have reads after the first write in a Firestore transaction. - Jeśli etap poprzedzający etap DML generuje wiele dokumentów z tym samym
__name__lub zwraca ten sam identyfikator dokumentu docelowego, każda mutacja jest przetwarzana sekwencyjnie:- W przypadku
upsert(...)iupdate(...): wiele mutacji dotyczących tego samego dokumentu jest zgodnych z semantyką „ostatnia wygrywa”, gdzie ostatnia przetworzona mutacja określa ostateczny stan dokumentu. - W przypadku
delete(...): pierwsza próba powoduje usunięcie dokumentu, a kolejne próby dotyczące tego samego dokumentu nie powodują żadnych działań. - W przypadku
insert(...): pierwsza próba powoduje utworzenie dokumentu, a kolejne próby dotyczące tego samego identyfikatora dokumentu kończą się błędemALREADY_EXISTS.
- W przypadku