Descripción
Conocer los valores distintos de un campo o una expresión de las etapas anteriores.
Sintaxis
La etapa distinct tiene una sintaxis similar a la de select. Toma una o más expresiones seleccionables para seleccionar y encontrar valores distintos. Se pueden usar cadenas cuando la expresión es solo una referencia de campo:
Node.js
const cities = await db.pipeline()
.collection('/cities')
.distinct("country")
.execute();
const cities = await db.pipeline()
.collection('/cities')
.distinct(
field("state").toLower().as("normalized_state"),
field("country"))
.execute();
Ejemplos de clientes
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();
Comportamiento
En términos de comportamientos de proyección, distinct es similar a select con deduplicación, por lo que cualquier expresión seleccionable disponible para select también se puede usar para distinct.
La etapa distinct funciona de manera similar a una etapa de agregación sin grupos.
Consulta también Etapa de agregación y Etapa de selección.
Cómo encontrar valores de campo distintos
Por ejemplo, para obtener una lista de todos los países de la siguiente colección 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'});
Puedes encontrar países distintos con las siguientes opciones:
Node.js
const cities = await db.pipeline()
.collection('/cities')
.distinct("country")
.execute();
que genera el siguiente resultado:
{country: "USA"}
{country: "Canada"}
{country: "Mexico"}
Salida distinta de expresiones
También puedes encontrar las combinaciones distintas de varios campos o expresiones más complicadas. Por ejemplo:
Node.js
const cities = await db.pipeline()
.collection('/cities')
.distinct(
field("state").toLower().as("normalized_state"),
field("country"))
.execute();
para obtener:
{country: "USA", normalized_state: "ca"}
{country: "USA", normalized_state: "ny"}
{country: "Canada", normalized_state: null}
{country: "Mexico", normalized_state: null}
Comportamientos de equivalencia
El comportamiento de equivalencia en valores distintos sigue la misma semántica que las igualdades.
Esto significa que los valores equivalentes, por ejemplo, los valores numéricos equivalentes desde el punto de vista matemático, independientemente de los tipos originales (números enteros de 32 bits, números enteros de 64 bits, números de punto flotante, números decimales, etcétera), se consideran el mismo valor distinto.
Por ejemplo, en una colección numerics con diferentes documentos que contienen valores foo de número entero de 32 bits 1, número entero de 64 bits 1L y punto flotante 1.0, respectivamente, distinct solo devolverá 1 resultado.
En estos casos, en los que hay diferentes valores equivalentes presentes en el conjunto de datos, el valor de salida del grupo puede ser cualquiera de estos valores equivalentes.
En este ejemplo, el valor de foo se podría devolver como 1, 1L o 1.0.
Incluso si parece determinístico, no debes intentar depender del comportamiento de un valor específico que se selecciona.
Uso de la memoria
La forma en que se ejecuta la etapa distinct depende de los índices disponibles. Cuando el optimizador de consultas no elige un índice adecuado, distinct requiere almacenar en búfer todos los valores distintos en la memoria.
En el caso de tener una gran cantidad de valores distintos o valores muy grandes (p. ej., distintos en valores enormes), es posible que esta etapa se quede sin memoria.
En esos casos, debes aplicar filtros para limitar el conjunto de datos en el que se realizará distinct o crear índices según lo recomendado para evitar un uso excesivo de la memoria.
Query Explain proporcionará información sobre el plan de ejecución de la consulta real y los datos de generación de perfiles para ayudar con la depuración.