Distinct

Descrizione

Trova tutte le combinazioni distinte di valori per una serie di espressioni.

La fase distinct(...) ha una sintassi simile a select(...), in quanto accetta una o più espressioni selezionabili. Le stringhe possono essere utilizzate quando l'espressione è solo un riferimento a un campo:

Esempi

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();

Comportamento

La fase distinct(...) funziona in modo simile a una fase aggregate(...) senza gruppi. Vedi anche aggregate(...) e select(...).

Trovare valori di campo distinti

Ad esempio, per ottenere un elenco di tutti i paesi nella seguente raccolta 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"});

È possibile trovare paesi distinti utilizzando:

Node.js

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

che genera il seguente risultato:

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

Output distinto delle espressioni

Puoi anche trovare le combinazioni distinte di più campi o espressioni più complesse. Ad esempio:

Node.js

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

per ottenere:

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

Comportamenti di equivalenza

Il comportamento di equivalenza su valori distinti segue la stessa semantica delle uguaglianze.

Ciò significa che i valori equivalenti, ad esempio i valori numerici matematicamente equivalenti, indipendentemente dai tipi originali (numeri interi a 32 bit, numeri interi a 64 bit, numeri in virgola mobile, numeri decimali e così via), sono considerati lo stesso valore distinto.

Ad esempio, in una raccolta numerics con documenti diversi contenenti valori foo di numeri interi a 32 bit 1, numeri interi a 64 bit 1L e numeri in virgola mobile 1.0 rispettivamente, distinct(...) restituirà un solo risultato.

In questi casi, in cui nel set di dati sono presenti valori equivalenti diversi, il valore di output del gruppo può essere uno qualsiasi di questi valori equivalenti. In questo esempio, il valore foo potrebbe essere restituito come 1, 1L o 1.0.

Anche se sembra deterministico, non devi tentare di fare affidamento sul comportamento di un valore specifico selezionato.

Utilizzo memoria

La modalità di esecuzione della fase distinct(...) dipende dagli indici disponibili. Quando l'ottimizzatore di query non sceglie un indice appropriato, distinct(...) richiede il buffering di tutti i valori distinti nella memoria.

Nel caso in cui si abbia un numero molto elevato di valori distinti o valori molto grandi (ad es. distinti su valori enormi), questa fase potrebbe esaurire la memoria.

In questi casi, devi applicare filtri per limitare il set di dati su cui eseguire distinct(...) o creare indici come consigliato per evitare un utilizzo eccessivo della memoria.

Query Explain fornisce informazioni sul piano di esecuzione della query effettivo e dati di profilazione per facilitare il debug.