---
title: "Obtener valores únicos para filtros dinámicos"
method: POST
path: "/analytics/filters"
tags: ["Filters"]
---

# Obtener valores únicos para filtros dinámicos

`POST /analytics/filters`

## Request

- Base URL: `http://localhost:8081`
- URL: `http://localhost:8081/analytics/filters`
- Auth: HTTP bearer

Obtiene valores únicos de campos específicos para construir filtros dinámicos.

Equivalente a `SELECT DISTINCT` en SQL o `db.collection.distinct()` en metadata store.

Los valores se filtran automáticamente por tenant basado en el JWT token.

## Request body

- FilterRequest
  - `queries` FilterQuery[], required: Lista de consultas para obtener valores de filtros
    - `collection` string, required: Nombre de la vista/tabla in the database. Ejemplos: `email_usage_daily`, `purchases`, `events` Debe ser una tabla de la lista blanca de la Analytics API (la que publica `GET /analytics/capabilities`). Cualquier otra es un 400 `INVALID_REQUEST` para toda la petición, antes de consultar BigQuery; el mensaje no repite el nombre.
    - `fields` string[], required: Lista de campos para obtener valores únicos
    - `filters` FilterCondition[]: Filtros adicionales para limitar los valores
      - `field` string, required: Nombre del campo a filtrar
      - `operator` 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'not_in' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'regex' | 'regex_i' | 'is_null' | 'is_not_null' | 'before' | 'after' | 'between' | 'array_contains' | 'array_not_contains' | 'array_contains_any' | 'array_length_eq' | 'array_length_gt', required: Operadores disponibles para filtros Analytics API. **Total: 28 operadores** organizados en 7 categorías. **Validación por tipo de dato**: El sistema valida automáticamente que el operador sea compatible con el tipo de dato del campo. ### Operadores por Tipo de Dato **TEXT** (15 operadores): - Comparación: `eq`, `neq`, `in`, `not_in` - Búsqueda: `contains`, `not_contains`, `starts_with`, `ends_with` - Regex: `regex`, `regex_i` (case-insensitive) - Null: `is_null`, `is_not_null` **NUMBER** (11 operadores): - Comparación: `eq`, `neq`, `gt`, `gte`, `lt`, `lte` - Arrays: `in`, `not_in` - Rangos: `between` - Null: `is_null`, `is_not_null` **DATE** (10 operadores): - Comparación: `eq`, `neq`, `gt`, `gte`, `lt`, `lte` - Temporales: `before`, `after`, `between` - Null: `is_null`, `is_not_null` - El valor es `YYYY-MM-DD` o fecha y hora ISO 8601 y se compara con el cast de la columna: - **Columna DATE** (`DATE(valor)`): todos los operadores comparan días. Un valor con hora u offset cuenta como el **día UTC de su instante** (`2024-01-02T23:30:00-05:00` → 2024-01-03). `eq v` selecciona las mismas filas que `gte v` y `lte v` juntos. - **Columna TIMESTAMP** (`TIMESTAMP(valor)`): `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `before` y `after` comparan el **instante**; una fecha sola es su medianoche UTC. Por ejemplo, `lte '2024-01-02'` no incluye el resto de ese día, y `eq '2024-01-02'` solo coincide con `2024-01-02 00:00:00 UTC`. Solo `between` incluye el día UTC completo del extremo final (`< día UTC siguiente`), igual que el fin de `timeRange`. **BOOLEAN** (3 operadores): `eq` / `neq` con `true` o `false`, y `exists`. `is_true`/`is_false` son operadores de segmentación, no de analytics (400). **ARRAY** (5 operadores): - Contenido: `array_contains`, `array_not_contains`, `array_contains_any` - Tamaño: `array_length_eq`, `array_length_gt` ### Ejemplos ```json // Text - contains { "field": "tenant_name", "operator": "contains", "value": "company" } // Number - range { "field": "emails_sent", "operator": "in_range", "value": [100, 1000] } // Date - before { "field": "send_date", "operator": "before", "value": "2024-12-31" } // Regex case-insensitive { "field": "email", "operator": "regex_i", "value": "^[a-z]+@gmail\\.com$" } // Empty check { "field": "description", "operator": "is_empty" } ``` ### Seguridad - **Regex**: Se valida que el patrón sea válido y no contenga construcciones peligrosas - **Regex y BigQuery (RE2)** (`regex`, `regex_i`): BigQuery evalúa el patrón con RE2, que no admite todo lo que admite una expresión regular de JavaScript. Un conjunto enumerado de construcciones incompatibles se rechaza con **400 `INVALID_ANALYTICS_VALUE` antes de lanzar la consulta** y sin repetir el patrón: lookahead/lookbehind (`(?=`, `(?!`, `(?<=`, `(?<!`), referencias hacia atrás (`\1`, `\k<n>`), escapes que RE2 no define (`\u`, `\c`, `\Z`…), `\x` mal formado (sin comprobar el rango del código en `\x{…}`), `\E` suelto, clases POSIX desconocidas y clases sin cerrar (`[]`, `[^]`). La validación **no es un parser RE2 completo**: otros patrones que RE2 no admite (por ejemplo `\p{…}` desconocido, un escape de carácter no ASCII, repeticiones de más de 1000, un rango que termina en una clase como `[a-\d]`, un código `\x{…}` por encima de `10FFFF`) pueden ser rechazados por BigQuery al ejecutar la consulta, con un error de servidor y sin devolver filas. - **Field names**: Solo se permiten caracteres alfanuméricos, underscore y punto - **Array values**: Los operadores de array requieren valores no vacíos
      - `value` union, required: Valor para la comparación. El tipo depende del operador: - **Comparación**: string, number, o boolean - **Arrays** (`in`, `nin`): array de valores - **Fechas**: string ISO 8601, `YYYY-MM-DD` o fecha y hora (`Z`, offset o sin zona = UTC). Cómo se compara según el tipo de la columna: ver `FilterOperator` (DATE) - **Between**: array con [inicio, fin]
        - string
        - number
        - boolean
        - union[]
          - union
            - string
            - number

## Response `200`

Valores únicos encontrados

- object
  - `success` boolean
  - `data` FilterResponse[]
    - `collection` string, required: Nombre de la colección consultada
    - `results` object, required: Resultados organizados por campo. Cada clave es un nombre de campo, cada valor es un array de valores únicos.
  - `timestamp` string, date-time

## Other responses

- `400`: Solicitud inválida
- `401`: No autorizado - Token JWT inválido o faltante. Los rechazos del middleware de autenticación usan el envelope `AuthError` (`{ success, message, code? }`); un `activeTenantId` mal formado devuelve `code: INVALID_ACTIVE_TENANT` (ver `components.responses.InvalidActiveTenant`), un token de tipo no admitido `code: INVALID_TOKEN_TYPE` con `message: Tipo de token no aceptado`, y un token de impersonación cuya sesión terminó `code: IMPERSONATION_SESSION_TERMINATED`.
- `403`: Acceso denegado antes de ejecutar ninguna consulta. Dos casos: - **Rol no admitido** (`error.code: FORBIDDEN`): las rutas de datos solo admiten tokens con rol ADMIN, OWNER o SUPERADMIN (los `campaign_service_token` de nev-api llevan rol ADMIN). Un token de fan (USER), STAFF, EXTERNAL o sin rol recibe 403. - **Selección ajena** (`code: ACTIVE_TENANT_FORBIDDEN`): la organización seleccionada (`activeTenantId`) no pertenece a la jerarquía actual de `tenantId`.
- `500`: Error interno del servidor
- `503`: No se pudo leer la jerarquía de tenants (MongoDB no disponible). Reintentable; nunca se sustituye por un ámbito parcial o global.

---

[API](https://skmtc.dev/nevent/apis/nevent-data-api.md) · [All operations](https://skmtc.dev/nevent/apis/nevent-data-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nevent/apis/nevent-data-api/revisions/81035d32c1c1?raw)
