Intermedio8 min de lectura

Ordenar DynamoDB por un atributo que cambia

Modelas una clave de ordenación alrededor de un atributo para poder consultar items en ese orden — y luego el atributo cambia. El status de un ticket, el estado de un pedido, la prioridad de una tarea. La regla de DynamoDB: no puedes actualizar un atributo de clave in place. Una clave primaria es inmutable durante la vida del item. Cambiar un valor que forma parte de la clave no es editar un item — es moverlo, y DynamoDB te obliga a hacerlo de forma explícita.

¿Puedes cambiar la clave de ordenación de DynamoDB?

No. Una clave de ordenación forma parte de la clave primaria, y los atributos de clave de DynamoDB son inmutables — UpdateItem no puede editar el valor de una clave de partición o de ordenación, y no hay operación de "mover item". Para cambiarla, borra el item viejo y pon uno nuevo, o deja el valor volátil en la clave de ordenación de un GSI.

  • Los atributos de clave son inmutables. No puedes hacer UpdateItem del valor de una clave de partición o de ordenación — DynamoDB no tiene operación de "mover item".
  • Para cambiar un valor de clave borras el item viejo y pones uno nuevo — idealmente en una transacción para que sea atómico.
  • Mejor: deja el valor volátil fuera de la clave de la tabla base y ponlo en la clave de ordenación de un GSI — las claves de GSI pueden cambiar, porque actualizar el item base solo repropaga la entrada del índice.
  • Elige claves de ordenación que no cambien (timestamps, ids inmutables) siempre que el patrón de acceso lo permita.

El problema: un status por el que quieres ordenar, y que no para de cambiar

Digamos que llevas un support desk y quieres listar los tickets de un equipo ordenados por status, así que pones el status en la clave de ordenación:

PK: TEAM#7   SK: STATUS#open#TICKET#8842

Ahora el ticket pasa a pending. Te gustaría solo hacer UpdateItem de la clave de ordenación a STATUS#pending#TICKET#8842 — pero DynamoDB rechaza cualquier escritura que cambie un atributo de clave. La clave es la dirección del item; no puedes editar la dirección in place. El status que elegiste para ordenar es exactamente lo que no se queda quieto.

Opción 1: borrar y recrear (de forma atómica)

Si el valor debe vivir en la clave de la tabla base, cambiarlo significa quitar el item viejo y escribir el nuevo:

1. DeleteItem  PK=TEAM#7  SK=STATUS#open#TICKET#8842
2. PutItem     PK=TEAM#7  SK=STATUS#pending#TICKET#8842  (same attributes)

Hazlo dentro de un TransactWriteItems para que el delete y el put tengan éxito o fallen juntos — si no, un crash entre medias pierde el ticket o lo duplica. Funciona, pero cada cambio de status son ahora dos escrituras más una transacción; bien para cambios ocasionales, caro para los calientes.

Opción 2: deja el valor mutable fuera de la clave base (preferido)

Haz que la clave de la tabla base sea algo inmutable (el id del ticket) y pon el valor volátil y ordenable en la clave de ordenación de un GSI.

Base:  PK: TICKET#8842   status: "open"   teamId: TEAM#7
GSI:   GSI1PK: TEAM#7    GSI1SK: STATUS#open#TICKET#8842

Ahora cambiar el status es un UpdateItem plano del atributo status del item base — que DynamoDB permite, porque status no es una clave de la tabla base. DynamoDB entonces repropaga la entrada del GSI automáticamente a su nueva posición ordenada. Una llamada a la API, con atomicidad resuelta por ti — sin transacción, sin baile de deletes (bajo el capó DynamoDB sigue borrando la entrada vieja del índice y escribiendo la nueva, así que un cambio indexado cuesta ~3 unidades de escritura frente a las ~4 de un delete-and-put transaccional).

No, es clave de ordenación de GSIStatus cambia de open a pending¿Está el valor en una clave de latabla base?Delete + recreate en unatransacciónUpdateItem plano; el GSI serepropaga

El GSI es de consistencia eventual y cuesta almacenamiento/escrituras extra — pero para un valor que cambia a menudo, eso es algo más barato (~3 vs 4 unidades de escritura) y mucho más simple que delete-and-recreate en cada cambio.

Diseñar las claves en DynoTable

Construye y previsualiza las condiciones de clave tanto para la lectura base como para la del GSI en el generador de expresiones de DynamoDB.

En DynoTable, luego eliges por qué índice corre una query y ves el valor volátil ordenarse en el GSI mientras el item base mantiene su clave inmutable — ambas lecturas lado a lado sobre datos reales.

Consultando un GSI ordenado por status mientras el item base mantiene una clave inmutable en DynoTable.
Consultando un GSI ordenado por status mientras el item base mantiene una clave inmutable en DynoTable.

Escollos + próximos pasos

  • Nunca intentes UpdateItem de un atributo de clave — se rechaza; los valores de clave están fijos durante la vida del item.
  • Si debes moverlo, haz delete+put en una transacción — nunca como dos escrituras sin guarda.
  • Prefiere claves base inmutables + un GSI para cualquier atributo por el que ordenas y mutas.
  • No olvides la consistencia eventual del GSI — la entrada reordenada aparece tras un breve retraso de propagación.
  • Relacionado: estrategias de sort-key, GSI vs LSI, transacciones.

¿Quieres ver cómo un atributo mutable se ordena en un GSI frente a la tabla base? Descarga DynoTable y explora tus índices directamente.

Coste de escritura: delete-and-put vs update de GSI

Comparación aproximada de WCU para un ticket de 1 KB en us-east-1 on-demand (la facturación real sigue las reglas de redondeo de AWS):

PatrónLlamadas APIImpacto típico de WCU
Delete + put transaccional en clave baseTransactWriteItems (2 ops)~2× tamaño del item por op en pricing de transacción
Update del atributo status; el GSI se repropagaUn UpdateItemEscritura base + escritura GSI (~2 WCU por item 1 KB + attrs proyectados)

El camino del GSI evita orquestación a nivel de aplicación y elimina la ventana donde un crash entre delete y put pierde la fila. Cambias consistencia eventual en la lectura del índice por escrituras más simples.

Modela el tamaño del item y la tasa de updates en la calculadora de pricing cuando los cambios de status disparan muchas veces por minuto.

GSI sparse para listas ordenadas por status

Si solo los tickets open necesitan una cola ordenada por status, usa un índice sparse: escribe GSI1PK = TEAM#7 y GSI1SK = STATUS#open#... solo mientras status = open. Cuando el ticket se cierra, quita u omite los atributos de clave del GSI en el update — el item sale del índice sin un delete-and-put en la clave de ordenación base.

Eso mantiene el índice pequeño y evita indexar tickets cerrados que nunca listas.

Claves base inmutables a preferir

Campo volátilSK de tabla baseMejor SK baseEl campo volátil vive en
Status del pedidoSTATUS#shipped#ORD#99ORD#99Sort del GSI o atributo
Prioridad de tareaP#1#TASK#12TASK#12Sort del GSI
Nombre visible de userNAME#alice#USER#5USER#5Atributo no-clave

Timestamps e ids inmutables (CREATED#2026-06-27T10:00:00Z, TICKET#8842) hacen claves de ordenación base estables cuando necesitas orden cronológico en la propia tabla base.

Diseña el GSI antes de codear

Mapea patrones de acceso en la herramienta de single-table design — introduce "listar tickets open por equipo, orden de prioridad" e inspecciona las plantillas sugeridas de GSI1PK / GSI1SK. Luego construye la condición de clave en el expression builder y emite una query paginada con el query builder para tests de integración.

Read-your-writes tras un cambio de status

Tras un UpdateItem, una lectura de consistencia fuerte en la tabla base muestra el nuevo status al instante. Una query en el GSI puede ir un poco por detrás. Los flujos de UI que redirigen a una cola ordenada por GSI deberían tolerar filas stale o re-fetch desde la tabla base por id cuando la precisión importa.

Actualizado