Query

Ejecutar consulta analítica flexible

Ejecuta consultas analíticas flexibles con agregaciones y filtros dinámicos.

El frontend puede definir:

  • Dimensiones: Campos para agrupar (GROUP BY)
  • Métricas: Campos para agregar (SUM, COUNT, AVG, etc.)
  • Filtros: Condiciones WHERE dinámicas
  • Granularidad temporal: Agregación por día, semana, mes, etc.
  • Ordenamiento: Campos y dirección
  • Límites: Número máximo de resultados

Todas las consultas incluyen automáticamente filtrado por tenant.

Dry Run (estimación de coste)

Añade ?dryRun=true para ejecutar un dry run nativo de BigQuery que valida la sintaxis SQL y estima los bytes que se procesarían, sin ejecutar la query (coste = $0). Ideal para que el frontend muestre estimaciones de coste antes de ejecutar queries pesadas.

  • Rate limit independiente: 200 req/min (no consume cuota de queries normales)
  • Precio estimado: $6.25/TB (BigQuery on-demand pricing)
  • La respuesta incluye el SQL generado para depuración
post/analytics/query

Request

  • Base URL: http://localhost:8081
  • URL: http://localhost:8081/analytics/query
  • Auth: HTTP bearer

Query parameters

dryRun'true' | '1'

Cuando es true o 1, ejecuta un dry run de BigQuery (validación de sintaxis

  • estimación de coste) sin ejecutar la query real. La respuesta incluye estimatedBytesProcessed, estimatedCostUSD y el SQL generado. Rate limit: 200 req/min (separado del límite de queries normales).

Request body

collectionstring required

Nombre de la vista/tabla base a consultar.

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 antes de consultar BigQuery, también en dryRun y en /analytics/export; el mensaje no repite el nombre.

sourceTablestring

Phase 4 - CTEs: Indica desde qué tabla/CTE se debe hacer el SELECT principal.

Si se especifica, el SELECT principal se hace desde este CTE en lugar de collection. Los filtros del main query NO se aplican cuando sourceTable es un CTE (data ya filtrada). Si no es uno de los CTE, debe ser una tabla de la lista blanca: si no, 400 INVALID_REQUEST sin repetir el nombre.

timeGranularity'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year' | 'fiscalQuarter' | 'fiscalYear'

Granularidad temporal para agregaciones.

Total: 9 granularidades (2 intra-day + 5 básicas + 2 fiscales).

Básicas (DATE_TRUNC)

Se aplica usando DATE_TRUNC in the database sobre campos de fecha.

  • day: Agrupa por día (YYYY-MM-DD)
  • week: Agrupa por semana (lunes como inicio)
  • month: Agrupa por mes (YYYY-MM)
  • quarter: Agrupa por trimestre calendario (Q1: Ene-Mar, Q2: Abr-Jun, Q3: Jul-Sep, Q4: Oct-Dic)
  • year: Agrupa por año calendario

Phase 4 - Intra-day (TIMESTAMP_TRUNC)

Se aplica usando TIMESTAMP_TRUNC para análisis de hora/minuto.

  • hour: Agrupa por hora (granularidad de 1 hora)
  • minute: Agrupa por minuto (granularidad de 1 minuto)

Phase 4 - Fiscal Periods (JOIN con dim_dates)

Usa JOIN con tabla dim_dates para períodos fiscales.

  • fiscalQuarter: Trimestre fiscal (FQ1: Jul-Sep, FQ2: Oct-Dic, FQ3: Ene-Mar, FQ4: Abr-Jun)
  • fiscalYear: Año fiscal (comienza en Julio, formato: FY2024)
  • Cobertura de dim_dates: 2020-01-01 a 2030-12-31. Fechas fuera de ese rango, o nulas, devuelven el período null.
groupByGroupByType[]

Phase 4: Tipos especiales de agrupación temporal (temporal extractors y fiscal periods).

Diferencia con dimensions:

  • groupBy: Extrae componentes (hourOfDay, dayOfWeek) o aplica formateo fiscal
  • dimensions: Agrupa por campos raw o con timeGranularity aplicado

Ejemplos: hourOfDay, dayOfWeek, fiscalQuarter, fiscalYear

limitinteger

Límite de resultados

offsetinteger

Número de filas del resultado final a saltar (paginación, #62 R-2). Se aplica tras having, sort y las comparativas, y va como parámetro (LIMIT … OFFSET …).

  • Las páginas solo son estables con un sort que ordene todas las filas (p. ej. por un id único); sin sort el orden no está garantizado.
  • Con limit: esa página. Sin limit: salta offset filas del resultado completo (sin tope, como sin offset).
  • 0 o ausente: el resultado de siempre.
  • offset > 0 con groupBy dayOfWeek/hourOfDay → 400 INVALID_REQUEST: esas franjas se rellenan después de la consulta y las páginas se solaparían.
  • Un valor que no sea un entero ≥ 0 → 400 INVALID_ANALYTICS_VALUE.
  • No aplica a ctes[], /analytics/export ni /analytics/filters.
distinctboolean

Deduplicación a nivel de query (NEV-1597).

Cuando true, genera SELECT DISTINCT en lugar de SELECT, eliminando filas duplicadas del resultado.

Compatibilidad:

  • ✅ Funciona con dimensions, filters, sort, limit
  • ⚠️ Ignorado silenciosamente si hay metrics con funciones de agregación (COUNT, SUM, etc.) — en ese caso se incluye un warning en metadata.warnings
  • ⚠️ No disponible con comparePeriods ni compareDimensions
  • 🔄 Valor por defecto: false (retrocompatible)

Ejemplo de uso:

{
  "collection": "user_tenants",
  "dimensions": [{ "field": "city" }],
  "distinct": true
}

Genera:

SELECT DISTINCT city
FROM `nevent-daf5f.mart_nevent_dev.user_tenants`
WHERE tenant_id = 'xxx'

Example request

{
  "collection": "email_usage_daily",
  "ctes": [
    {
      "name": "tickets_per_purchase",
      "collection": "purchase_tickets",
      "dimensions": [
        {
          "field": "send_date",
          "alias": "fecha"
        }
      ],
      "metrics": [
        {
          "field": "emails_sent",
          "alias": "total_emails",
          "condition": {
            "field": "send_date"
          },
          "params": {
            "delimiter": " | ",
            "limit": 20
          }
        }
      ],
      "filters": [
        {
          "field": "send_date"
        }
      ],
      "timeRange": {
        "start": "2024-01-01",
        "end": "2024-12-31"
      },
      "sort": {
        "field": "month"
      }
    }
  ],
  "sourceTable": "tickets_per_purchase",
  "dimensions": [
    {
      "field": "send_date",
      "alias": "fecha"
    }
  ],
  "metrics": [
    {
      "field": "emails_sent",
      "alias": "total_emails",
      "condition": {
        "field": "send_date"
      },
      "params": {
        "delimiter": " | ",
        "limit": 20
      }
    }
  ],
  "timeRange": {
    "start": "2024-01-01",
    "end": "2024-12-31"
  },
  "filters": [
    {
      "field": "send_date"
    }
  ],
  "having": [
    {
      "field": "send_date"
    }
  ],
  "sort": {
    "field": "month"
  },
  "limit": 100,
  "distinct": true,
  "comparePeriods": {
    "current": {
      "start": "2025-12-01",
      "end": "2025-12-31",
      "name": "Diciembre 2025"
    },
    "previous": {
      "start": "2024-12-01",
      "end": "2024-12-31",
      "name": "Diciembre 2024"
    }
  },
  "compareDimensions": {
    "active": true,
    "dimensions": [
      {
        "field": "eventId",
        "value": "6940193688d2ee658320f9e5",
        "name": "Euforia Festival 2025"
      }
    ]
  }
}

Response

Consulta ejecutada exitosamente

successboolean
timestampstring date-time

Example response

{
  "success": true,
  "data": {
    "metadata": {
      "totalRows": 150,
      "executionTime": 1263,
      "query": "SELECT SUM(`emails_sent`) as `total_emails` FROM `nevent-daf5f.mart_nevent_dev.email_usage_daily` WHERE `tenant_id` = '72ef6ce8-...' AND `send_date` >= DATE('2024-01-01')",
      "comparisonMetadata": {
        "comparisonDimensions": [
          {
            "field": "event_id",
            "value": "6597d9b3c9a57d0f00fcf194",
            "label": "6597d9b3c9a57d0f00fcf194",
            "columnName": "revenue_6597d9b3c9a57d0f00fcf194"
          }
        ],
        "totalColumn": "revenue_total"
      },
      "warnings": [
        "distinct was ignored because aggregation metrics (COUNT, SUM, etc.) are present."
      ]
    }
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.