Distinct (Transformation Stage)

Descrição

Encontra todas as combinações distintas de valores para uma série de expressões.

A etapa distinct(...) tem uma sintaxe semelhante à de select(...), já que usa uma ou mais expressões selecionáveis. Strings podem ser usadas quando a expressão é apenas uma referência de campo:

Exemplos

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

Comportamento

A etapa distinct(...) funciona de maneira semelhante a uma etapa aggregate(...) sem grupos. Consulte também aggregate(...) e select(...).

Encontrar valores de campo distintos

Por exemplo, para receber uma lista de todos os países na seguinte coleção 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"});

Para encontrar países distintos, use:

Node.js

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

que gera o seguinte resultado:

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

Saída distinta de expressões

Você também pode encontrar as combinações distintas de vários campos ou expressões mais complicadas. Exemplo:

Node.js

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

para ter:

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

Comportamentos de equivalência

O comportamento de equivalência em valores distintos segue a mesma semântica das igualdades.

Isso significa que valores equivalentes, por exemplo, valores numéricos matematicamente equivalentes, independentemente dos tipos originais (número inteiro de 32 bits, número inteiro de 64 bits, números de ponto flutuante, números decimais etc.), são considerados o mesmo valor distinto.

Por exemplo, em uma coleção numerics com diferentes documentos que contêm valores foo de números inteiros de 32 bits 1, 64 bits 1L e ponto flutuante 1.0, respectivamente, distinct(...) vai retornar apenas um resultado.

Nesses casos, em que há valores equivalentes diferentes no conjunto de dados, o valor de saída do grupo pode ser qualquer um desses valores equivalentes. Neste exemplo, o valor de foo pode ser retornado como 1, 1L ou 1.0.

Mesmo que pareça determinista, não tente confiar no comportamento de um valor específico sendo selecionado.

Uso da memória

A execução da etapa distinct(...) depende dos índices disponíveis. Quando não há um índice adequado escolhido pelo otimizador de consultas, distinct(...) exige o buffer de todos os valores distintos na memória.

Se houver um número muito grande de valores distintos ou valores muito grandes (por exemplo, distintos em valores enormes), essa etapa poderá ficar sem memória.

Nesses casos, aplique filtros para limitar o conjunto de dados a ser usado em distinct(...) ou crie índices conforme recomendado para evitar o uso excessivo de memória.

A explicação da consulta fornece informações sobre o plano de execução real da consulta e dados de criação de perfil para ajudar na depuração.