Niepowtarzalne

Opis

Znajdź wszystkie różne kombinacje wartości dla serii wyrażeń.

Etap distinct(...) ma podobną składnię do etapu select(...), ponieważ przyjmuje co najmniej 1 wyrażenie, które można wybrać. Ciągów tekstowych można używać, gdy wyrażenie jest tylko odwołaniem do pola:

Przykłady

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

var cities = db.pipeline()
    .collection("cities")
    .distinct("country")
    .execute()

cities = db.pipeline()
    .collection("cities")
    .distinct(
        field("state").toLower().alias("normalizedState"),
        field("country")
    )
    .execute()

Java

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();
Go
cities1, err := client.Pipeline().Collection("cities").Distinct(firestore.Fields("country")).Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

cities2, err := client.Pipeline().Collection("cities").
	Distinct(firestore.Fields(
		firestore.ToLower(firestore.FieldOf("state")).As("normalizedState"),
		firestore.FieldOf("country"),
	)).
	Execute(ctx).Results().GetAll()
if err != nil {
	fmt.Fprintf(w, "GetAll failed: %v", err)
	return err
}

Zachowanie

Etap distinct(...) działa podobnie do etapu aggregate(...) bez grup. Zobacz też aggregate(...)select(...).

Znajdowanie odrębnych wartości pól

Aby na przykład uzyskać listę wszystkich krajów w tej kolekcji:cities

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"});

Poszczególne kraje można znaleźć za pomocą:

Node.js

const cities = await db.pipeline()
  .collection("/cities")
  .distinct("country")
  .execute();

co daje ten wynik:

{ country: "USA" }
{ country: "Canada" }
{ country: "Mexico" }

Różne dane wyjściowe wyrażeń

Możesz też znaleźć różne kombinacje wielu pól lub bardziej złożone wyrażenia. Przykład:

Node.js

const cities = await db.pipeline()
  .collection("/cities")
  .distinct(
    field("state").toLower().as("normalized_state"),
    field("country"))
  .execute();

aby uzyskać:

{ country: "USA", normalized_state: "ca" }
{ country: "USA", normalized_state: "ny" }
{ country: "Canada", normalized_state: null }
{ country: "Mexico", normalized_state: null }

Zachowania równoważne

Zachowanie równoważności w przypadku różnych wartości jest takie samo jak w przypadku równości.

Oznacza to, że równoważne wartości, np. matematycznie równoważne wartości numeryczne, niezależnie od pierwotnych typów (liczby całkowite 32-bitowe, liczby całkowite 64-bitowe, liczby zmiennoprzecinkowe, liczby dziesiętne itp.), są traktowane jako ta sama odrębna wartość.

Na przykład w kolekcji numerics z różnymi dokumentami zawierającymi wartości foo odpowiednio 32-bitowej liczby całkowitej 1, 64-bitowej liczby całkowitej 1L i liczby zmiennoprzecinkowej 1.0 funkcja distinct(...) zwróci tylko 1 wynik.

W takich przypadkach, gdy w zbiorze danych występują różne równoważne wartości, wartość wyjściowa grupy może być dowolną z nich. W tym przykładzie wartość foo może zostać zwrócona jako 1, 1L lub 1.0.

Nawet jeśli wydaje się, że jest to deterministyczne, nie próbuj polegać na zachowaniu polegającym na wybraniu jednej konkretnej wartości.

Wykorzystanie pamięci

Sposób wykonania etapu distinct(...) zależy od dostępnych indeksów. Jeśli optymalizator zapytań nie wybierze odpowiedniego indeksu, funkcja distinct(...) wymaga buforowania wszystkich odrębnych wartości w pamięci.

Jeśli masz bardzo dużą liczbę różnych wartości lub wartości są bardzo duże (np. różne wartości w przypadku bardzo dużych liczb), na tym etapie może zabraknąć pamięci.

W takich przypadkach należy zastosować filtry, aby ograniczyć zbiór danych, na którym ma być przeprowadzana operacja distinct(...), lub utworzyć indeksy zgodnie z zaleceniami, aby uniknąć dużego zużycia pamięci.

Funkcja Query Explain dostarczy informacji o rzeczywistym planie wykonywania zapytania i danych profilowania, które pomogą w debugowaniu.