Saltar a contenido

Agregaciones

Cuatro atajos y un método general. Todos aceptan los mismos filtros que find_many, y devuelven un AggregationResult.

Los atajos

dao.sum(agg_fields=['importe'], activo=True)
dao.mean(agg_fields=['importe'])
dao.max(agg_fields=['importe', 'unidades'])
dao.min(agg_fields=['importe'])
res = dao.sum(agg_fields=['importe'])
res.rows[0].data          # {'sum_importe': 1234.5}

agg — varias operaciones, GROUP BY y ranking

from database.public import AggRequest, AggField, GroupByField, DatetimeTrunc, AggOrderBy
res = dao.agg(AggRequest(
    aggregations={'sum': ['importe'], 'count': ['id']},
))
res.rows[0].group     # {}
res.rows[0].data      # {'sum_importe': 1234.5, 'count_id': 42}
res = dao.agg(AggRequest(
    aggregations={'sum': ['importe'], 'count': ['id']},
    group_by=['estado', GroupByField(field='creado_en', trunc=DatetimeTrunc.month)],
))

for row in res.rows:
    print(row.group, row.data)
    # {'estado': 'publicado', 'creado_en_month': '2026-09-01'} {'sum_importe': 900.0, ...}
res = dao.agg(AggRequest(
    aggregations={'sum': [AggField(expr='ingresos-costes', alias='margen')]},
    group_by=['estado'],
))
res = dao.agg(AggRequest(
    aggregations={'count': ['id']},
    group_by=['referencia_producto'],
    order_by=[AggOrderBy(operation='count', field='id', direction='desc')],
    limit=10,
))

Las piezas

Clase Para qué
AggRequest Qué calcular: aggregations, group_by, order_by, limit
AggField Una expresión aritmética entre columnas, con alias opcional
GroupByField Un campo de agrupación, con trunc para fechas
DatetimeTrunc La granularidad del truncado temporal
AggOrderBy Ordenar por una columna calculada: operation + field + direction

Operaciones soportadas: sum, mean, max, min, count.

DatetimeTrunc admite year, quarter, month, week, day, hour, minute (vía DATE_TRUNC) y los intervalos 12h, 6h, 3h, 30min, 15min (vía DATE_BIN). La clave resultante en AggRow.group es <campo>_<trunc>, por ejemplo creado_en_month.

Reglas del group_by

  • Un str equivale a GroupByField(field=..., trunc=None).
  • Las columnas DATETIME / TIMESTAMP exigen trunc explícito: agrupar por un instante no agrupa nada.
  • Las columnas FLOAT / DOUBLE / DECIMAL / NUMERIC / REAL no se pueden agrupar.

El resultado

res.success            # bool
res.rows               # List[AggRow] — cada una con .group y .data
res.group_by           # los campos de agrupación aplicados
res.processed_fields   # los campos que se han podido calcular
res.warnings           # lo que se ha ignorado, y por qué
res.errors
res.metadata

Sin group_by, rows tiene una sola fila con group = {}. Con él, una por combinación.

Las claves de data son <operacion>_<campo> (sum_importe, count_id), o el alias si lo declaraste.

Con filtros y RLS

res = dao.agg(
    AggRequest(aggregations={'sum': ['importe']}),
    min_creado_en=datetime(2026, 1, 1),
    estado='publicado',
    rls=RLS(target_model=Empresa, target_column='id', values=[1, 2]),
)

verbose=True emite un log detallado de cada campo, expresión y fila procesada — útil cuando una agregación devuelve menos de lo que esperabas.