Distinct

Description

Recherchez toutes les combinaisons distinctes de valeurs pour une série d'expressions.

L'étape distinct(...) a une syntaxe semblable à select(...), car elle accepte une ou plusieurs expressions sélectionnables. Les chaînes peuvent être utilisées lorsque l'expression n'est qu'une référence de champ :

Exemples

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

Comportement

L'distinct(...) étape fonctionne de la même manière qu'une aggregate(...) étape sans groupes. Consultez également aggregate(...) et select(...).

Rechercher des valeurs de champ distinctes

Par exemple, pour obtenir la liste de tous les pays de la collection cities suivante :

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

Vous pouvez trouver les pays distincts à l'aide de :

Node.js

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

qui génère le résultat suivant :

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

Sortie distincte des expressions

Vous pouvez également trouver les combinaisons distinctes de plusieurs champs ou des expressions plus complexes. Exemple :

Node.js

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

pour obtenir :

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

Comportements d'équivalence

Le comportement d'équivalence sur les valeurs distinctes suit la même sémantique que les égalités.

Cela signifie que les valeurs équivalentes, par exemple les valeurs numériques mathématiquement équivalentes, quels que soient les types d'origine (entier 32 bits, entier 64 bits, nombres à virgule flottante, nombres décimaux, etc.), sont considérées comme la même valeur distincte.

Par exemple, dans une collection numerics avec différents documents contenant foo valeurs d'entier 32 bits 1, d'entier 64 bits 1L et de virgule flottante 1.0 respectivement, distinct(...) ne renverra qu'un seul résultat.

Dans ce cas, si différentes valeurs équivalentes sont présentes dans l'ensemble de données, la valeur de sortie du groupe peut être n'importe laquelle de ces valeurs équivalentes. Dans cet exemple, cette valeur de foo peut être renvoyée sous la forme 1, 1L ou 1.0.

Même si cela semble déterministe, vous ne devez pas essayer de vous appuyer sur le comportement d'une valeur spécifique sélectionnée.

Utilisation de la mémoire

L'exécution de l'étape distinct(...) dépend des index disponibles. Lorsqu'aucun index approprié n'est choisi par l'optimiseur de requêtes, distinct(...) nécessite la mise en mémoire tampon de toutes les valeurs distinctes.

Si le nombre de valeurs distinctes est très élevé ou si les valeurs sont très volumineuses (par exemple, distinctes sur des valeurs énormes), cette étape peut manquer de mémoire.

Dans ce cas, vous devez appliquer des filtres pour limiter l'ensemble de données sur lequel effectuer distinct(...), ou créer des index comme recommandé pour éviter une utilisation importante de la mémoire.

Query Explain fournit des informations sur le plan d'exécution réel de la requête et les données de profilage pour faciliter le débogage.