Distinct (Transformationsphase)
Beschreibung
Findet alle eindeutigen Kombinationen von Werten für eine Reihe von Ausdrücken.
Die Phase distinct(...) hat eine ähnliche Syntax wie select(...), da sie einen oder
mehr auswählbare Ausdrücke akzeptiert. Strings können verwendet werden, wenn der Ausdruck nur eine Feldreferenz ist:
Beispiele
Node.js
let cities = await db.pipeline() .collection("cities") .distinct("country") .execute(); cities = await db.pipeline() .collection("cities") .distinct( field("state").toLower().as("normalizedState"), field("country")) .execute();
Web
let cities = await execute(db.pipeline() .collection("cities") .distinct("country")); cities = await execute(db.pipeline() .collection("cities") .distinct( field("state").toLower().as("normalizedState"), field("country")));
Swift
let results = try await db.pipeline() .collection("books") .distinct([ Field("author").toUpper().as("author"), Field("genre") ]) .execute()
Kotlin
Android
var cities = db.pipeline() .collection("cities") .distinct("country") .execute() cities = db.pipeline() .collection("cities") .distinct( field("state").toLower().alias("normalizedState"), field("country") ) .execute()
Java
Android
Task<Pipeline.Snapshot> cities; cities = db.pipeline() .collection("cities") .distinct("country") .execute(); cities = db.pipeline() .collection("cities") .distinct( field("state").toLower().alias("normalizedState"), field("country")) .execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import Field cities = client.pipeline().collection("cities").distinct("country").execute() cities = ( client.pipeline() .collection("cities") .distinct(Field.of("state").to_lower().as_("normalizedState"), "country") .execute() )
Java
Pipeline.Snapshot cities1 = firestore.pipeline().collection("cities").distinct("country").execute().get(); Pipeline.Snapshot cities2 = firestore .pipeline() .collection("cities") .distinct(toLower(field("state")).as("normalizedState"), field("country")) .execute() .get();
Verhalten
Die distinct(...) Phase funktioniert ähnlich wie eine
aggregate(...) Phase ohne Gruppen. Weitere Informationen finden Sie unter
aggregate(...) und
select(...).
Eindeutige Feldwerte finden
Beispiel: So rufen Sie eine Liste aller Länder in der folgenden cities-Sammlung ab:
Node.js
await db.collection("cities").doc("SF").set({name: "San Francisco", state: "CA", country: "USA"});
await db.collection("cities").doc("LA").set({name: "Los Angeles", state: "CA", country: "USA"});
await db.collection("cities").doc("NY").set({name: "New York", state: "NY", country: "USA"});
await db.collection("cities").doc("TOR").set({name: "Toronto", state: null, country: "Canada"});
await db.collection("cities").doc("MEX").set({name: "Mexico City", state: null, country: "Mexico"});
Eindeutige Länder können mit folgender Abfrage gefunden werden:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.distinct("country")
.execute();
Dadurch wird das folgende Ergebnis generiert:
{ country: "USA" }
{ country: "Canada" }
{ country: "Mexico" }
Eindeutige Ausgabe von Ausdrücken
Sie können auch die eindeutigen Kombinationen mehrerer Felder oder komplizierterer Ausdrücke finden. Beispiel:
Node.js
const cities = await db.pipeline()
.collection("/cities")
.distinct(
field("state").toLower().as("normalized_state"),
field("country"))
.execute();
Ergebnis:
{ country: "USA", normalized_state: "ca" }
{ country: "USA", normalized_state: "ny" }
{ country: "Canada", normalized_state: null }
{ country: "Mexico", normalized_state: null }
Verhalten bei Äquivalenz
Das Verhalten bei der Äquivalenz von eindeutigen Werten folgt derselben Semantik wie Gleichheiten.
Das bedeutet, dass äquivalente Werte, z. B. mathematisch äquivalente numerische Werte, unabhängig von den ursprünglichen Typen (32-Bit-Ganzzahl, 64-Bit-Ganzzahl, Gleitkommazahlen, Dezimalzahlen usw.) als derselbe eindeutige Wert betrachtet werden.
Beispiel: In einer Sammlung numerics mit verschiedenen Dokumenten, die
foo Werte vom Typ 32-Bit-Ganzzahl 1, 64-Bit-Ganzzahl 1L und Gleitkommazahl 1.0
enthalten, gibt distinct(...) nur ein Ergebnis zurück.
In solchen Fällen, in denen verschiedene äquivalente Werte im Dataset vorhanden sind, kann der Ausgabewert der Gruppe jeder dieser äquivalenten Werte sein.
In diesem Beispiel kann der Wert von foo als 1, 1L oder 1.0 zurückgegeben werden.
Auch wenn es deterministisch erscheint, sollten Sie sich nicht darauf verlassen, dass ein bestimmter Wert ausgewählt wird.
Arbeitsspeichernutzung
Wie die Phase distinct(...) ausgeführt wird, hängt von den verfügbaren Indexen ab. Wenn der Abfrageoptimierer keinen geeigneten Index auswählt, müssen bei distinct(...) alle eindeutigen Werte im Arbeitsspeicher gepuffert werden.
Wenn eine sehr große Anzahl eindeutiger Werte vorhanden ist oder die Werte sehr groß sind (z.B. eindeutige Werte für sehr große Werte), kann der Arbeitsspeicher für diese Phase nicht ausreichen.
In solchen Fällen sollten Sie Filter anwenden, um das Dataset zu beschränken, auf das distinct(...) angewendet wird, oder Indexe wie empfohlen erstellen, um eine hohe Arbeitsspeichernutzung zu vermeiden.
Mit „Query Explain“ erhalten Sie Informationen zum tatsächlichen Abfrageausführungsplan und Profiling-Daten, die bei der Fehlerbehebung helfen.