Principiante9 min de lectura

Cómo hacer COUNT, SUM y agregar en DynamoDB

DynamoDB tiene exactamente un agregado integrado: contar los ítems coincidentes con Select=COUNT. No hay SUM, AVG, MIN ni MAX nativos. E incluso el conteo que puedes obtener lee (y factura) cada ítem que contó. Esta guía cubre qué se admite realmente, las aproximaciones a las que recurre la gente, y cómo ejecutar COUNT/SUM/AVG reales sobre una tabla cuando los necesitas.

¿Puede DynamoDB hacer SUM, COUNT y funciones de agregado?

En su mayoría, no. El único agregado integrado de DynamoDB es Select=COUNT, que devuelve el número de ítems coincidentes pero aun así lee (y factura) cada ítem. No hay SUM, AVG, MIN ni MAX nativos, y PartiQL tampoco añade ninguno. Para agregados reales con GROUP BY, pliégalos en tu aplicación, mantén un contador, o ejecuta SQL en el SQL Workbench de DynoTable.

  • Select=COUNT devuelve el número de ítems coincidentes, pero DynamoDB aún lee cada ítem para producirlo — pagas el costo de lectura completo de Scan/Query, no un costo barato de "conteo".
  • No hay SUM, AVG, MIN ni MAX nativos. Las operaciones de lectura de DynamoDB devuelven ítems; no los pliegan en un número. PartiQL tampoco añade agregados.
  • DescribeTable.ItemCount es gratis pero aproximado y se actualiza solo "aproximadamente cada seis horas" — bien para un panel, mal para cualquier cosa exacta.
  • Para COUNT/SUM/AVG/MIN/MAX exactos (con GROUP BY), agrega en tu aplicación, mantén un contador, o ejecútalo en el SQL Workbench de DynoTable (más abajo).

Contar ítems: Select=COUNT

Tanto Query como Scan aceptan un parámetro Select. Ponlo en COUNT y la respuesta lleva los conteos en lugar de los ítems:

aws dynamodb scan \
  --table-name Orders \
  --select COUNT \
  --filter-expression "#s = :open" \
  --expression-attribute-names '{"#s":"status"}' \
  --expression-attribute-values '{":open":{"S":"OPEN"}}'

La respuesta te da dos números (AWS: Counting the items in the results):

  • Count — "el número de ítems que quedan, después de aplicar una filter expression (si está presente)."
  • ScannedCount — "el número de ítems evaluados, antes de aplicar cualquier ScanFilter." Sin filtro, ScannedCount es lo mismo que Count.

Si solo tienes la partition key y necesitas contar duplicados dentro de ella, la condición + filtro que pasas es exactamente lo que genera el DynamoDB Expression Builder — los mapas KeyConditionExpression, FilterExpression y ExpressionAttributeNames/Values de arriba — sin escapar el JSON a mano.

Dos pegas más que muerden a quienes cuentan tablas grandes:

  • El límite de página de 1 MB sigue aplicándose. "If the size of the Scan result set is larger than 1 MB, ScannedCount and Count represent only a partial count of the total items" (AWS Scan docs). Tienes que paginar con LastEvaluatedKeyExclusiveStartKey y mantener un total acumulado para obtener el número real — el mismo bucle cubierto en paginación de DynamoDB.
  • Un Query estrecho le gana a un Scan. Select=COUNT en un Query mide solo los ítems de la partición objetivo, no toda la tabla. Si puedes fijar una partition key (tabla base o un GSI), cuenta allí — es la diferencia de costo Query-vs-Scan aplicada al conteo.

Select=COUNT vs ItemCount (y por qué está desactualizado)

DescribeTable devuelve un ItemCount (y TableSizeBytes) gratis, sin costo de lectura. La trampa está en la referencia de la API en sí: "DynamoDB updates this value approximately every six hours. Recent changes might not be reflected in this value." Así que puede quedarse muy por detrás del estado real de tu tabla.

Select=COUNTDescribeTable.ItemCount
ExactitudExacto (para el conjunto coincidente)Aproximado
FrescuraEn vivoActualizado ~cada 6 horas
CostoLee + factura cada ítem contadoGratis (metadatos)
Puede filtrar / contar un subconjuntoSí (filter expression)No — solo tabla entera

Usa ItemCount para una idea aproximada de "qué tan grande es esta tabla" o un panel. Usa Select=COUNT cuando necesites un número exacto, filtrado o actual — y acepta el costo de lectura. Para cualquier cosa realmente en vivo y gratis, lleva tú mismo un contador (ver Patrones de agregación más abajo).

Por qué no hay SUM/AVG/MIN/MAX nativos

Las operaciones de lectura de DynamoDB devuelven ítems. No hay planificador de consultas que pliegue un conjunto de resultados en un escalar, así que no hay nada con qué calcular un SUM o un AVG. Contar es el único pliegue que ofrece la API, vía Select=COUNT.

PartiQL no cambia esto. La gramática de SELECT de PartiQL es SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …], donde la expresión es "a projection formed from the * wildcard or a projection list of one or more attribute names or document paths." No hay función de agregado ni cláusula GROUP BY en esa gramática — y ORDER BY toma una {{key}}, documentada como "a hash key or a sort key to use to order returned results." Cada SELECT de PartiQL aún se compila a un GetItem, Query o Scan, así que SELECT SUM(total) FROM "Orders" sencillamente no es expresable. (Más sobre el techo de PartiQL en PartiQL vs SQL.)

Patrones de agregación (contadores, streams, del lado de la app)

Como DynamoDB no agrega por ti, los patrones establecidos empujan el trabajo a otra parte:

  • Ítem contador mantenido. Mantén un ítem dedicado (p. ej. PK = "STATS#orders") y haz ADD a un atributo numérico en cada escritura con un UpdateItem. Leer el agregado es entonces un único GetItem — exacto y barato, pero tú eres dueño de la lógica de incremento, su consistencia y la contención si un contador recibe muchos golpes.
  • DynamoDB Streams → agregador. Habilita un stream y conéctalo a un Lambda que actualice totales acumulados (conteos, sumas) a medida que cambian los ítems. Según los AWS Streams docs, puedes configurar el StreamViewType del stream para que cada registro lleve el NEW_AND_OLD_IMAGES — "both the new and the old images of the item" — suficiente para mantener agregados estilo SUM actualizados sin re-escanear. Los registros del stream están sujetos a una vida de 24 horas ("the stream records within a shard are removed automatically after 24 hours"), así que el consumidor tiene que ir al día.
  • Pliegue del lado de la app. Pagina por los ítems coincidentes y acumula el SUM/AVG/MIN/MAX en tu propio código. Correcto, pero lee (y factura) cada ítem cada vez — el mismo perfil de costo que Select=COUNT, más la transferencia de datos.
  • Descargar a analítica. Para agregación analítica pesada o ad-hoc, exporta la tabla a S3 y consúltala con Athena, o vuélcala en streaming a un almacén. Según los AWS export-to-S3 docs, exportar "doesn't consume read capacity units" y te permite "perform analytics and complex queries using AWS services such as Athena" — el camino recomendado por AWS una vez que has superado la agregación por petición.

Cada uno cambia simplicidad por contabilidad en tiempo de escritura (contadores, streams) o por costo en tiempo de lectura (escaneos del lado de la app). Ningún patrón hace que DynamoDB en sí calcule un SUM gratis. La versión con agrupación de este compromiso — agregar por clave en lugar de sobre toda la tabla — tiene su propia guía: DynamoDB GROUP BY.

Ejecutar COUNT/SUM/AVG en el SQL Workbench de DynoTable

Cuando solo necesitas la respuesta — "cuántos pedidos OPEN, y cuál es su total" — sin escribir un bucle de scan paginado ni un Lambda, el SQL Workbench de DynoTable ejecuta agregados reales. Materializa tus tablas a través del motor real Query/Scan de DynamoDB, y luego ejecuta tu SQL completo encima: SQL dentro de las reglas de patrones de acceso de DynamoDB.

-- Runs in the DynoTable Workbench (NOT in PartiQL):
SELECT status,
       COUNT(*)        AS orders,
       SUM(total)      AS revenue,
       AVG(total)      AS avg_order,
       MIN(total)      AS smallest,
       MAX(total)      AS largest
FROM orders
GROUP BY status
ORDER BY revenue DESC

Eso es COUNT, SUM, AVG, MIN, MAX, GROUP BY y ORDER BY — ninguno de los cuales DynamoDB o PartiQL pueden expresar — en una sola sentencia. Esta es la misma cuña analítica que SQL para DynamoDB; para la historia completa de agrupación mira DynamoDB GROUP BY.

El Workbench es honesto sobre el modelo de acceso de debajo, no un pretend-Postgres:

  • Las filas aún vienen a través del Query/Scan real de DynamoDB. Un GROUP BY sobre una tabla entera sigue siendo un Scan por debajo — el Workbench expone ese costo en lugar de ocultarlo, el mismo compromiso Query-vs-Scan.
  • Los agregados se ejecutan sobre los atributos escalares materializados después de que las filas aterrizan.

Preguntas frecuentes

¿Puedo contar ítems en DynamoDB sin escanear? No exactamente. Para un conteo exacto y actual debes leer los ítems — Select=COUNT aún mide cada ítem contado. Las únicas opciones sin scan son el aproximado DescribeTable.ItemCount (actualizado ~cada 6 horas) o un ítem contador que mantengas tú mismo en cada escritura.

¿Cómo cuento ítems por un GSI? Ejecuta Query (o Scan) contra el índice con Select=COUNT. Contar vía una partición estrecha de GSI es mucho más barato que escanear la tabla base, porque solo lees los ítems de esa partición del índice — modela el índice en torno al conteo que necesitas.

¿Es preciso DescribeTable.ItemCount? Es aproximado. La referencia de la API indica que DynamoDB actualiza ItemCount y TableSizeBytes "approximately every six hours," y que "recent changes might not be reflected in this value." No lo uses donde importe un número exacto o en vivo.

¿Puede DynamoDB hacer SUM o AVG? No de forma nativa, ni en PartiQL — la gramática de SELECT de PartiQL no tiene funciones de agregado. Agrega en tu aplicación, mantén un contador (opcionalmente vía DynamoDB Streams), o ejecuta el SUM/AVG en el SQL Workbench de DynoTable.

¿Cuál es la diferencia entre Count y ScannedCount? ScannedCount es cuántos ítems evaluó DynamoDB antes de tu filtro; Count es cuántos quedan después. Son iguales cuando no hay filter expression. Una brecha grande entre ambos significa un conteo ineficiente.


¿Necesitas sumar, promediar o agrupar tus datos de DynamoDB sin escribir un bucle de scan? Descarga DynoTable y ejecútalo en una pestaña de Workbench. ¿Primero comparando clientes? Mira cómo se posiciona frente a una GUI sencilla de DynamoDB.

Actualizado