Claves de ordenación compuestas en DynamoDB
Una es una clave de partición más una clave de
ordenación. El truco que la hace potente es lo que pones dentro de la sort
key: codifica una jerarquía como una sola cadena delimitada, y un solo Query
lee un subárbol entero en orden de sort — sin joins, sin recursión, sin un
segundo round-trip.
¿Cómo funcionan las claves de ordenación compuestas en DynamoDB?
Una sort key compuesta empaqueta una jerarquía en una sola cadena delimitada — root/photos/2026/ — que DynamoDB guarda en orden de bytes UTF-8. Como el layout ya coincide con el árbol, un solo Query con begins_with(SK, "root/photos/") lee un subárbol entero en orden de path. Sin joins, sin recursión, sin un segundo round-trip — solo un scan de prefijo sobre un contiguo.
- La sort key es una cadena ordenable, no solo un ID. Empaqueta un path en
ella —
root/photos/2026/— y DynamoDB guarda los items de la partición en orden de bytes UTF-8 automáticamente. - Un delimitador convierte los matches de prefijo en lecturas de subárbol.
begins_with(SK, "root/photos/")devuelve cada descendiente de esa carpeta en una sola query. - Las sort keys admiten condiciones de rango, no filtros arbitrarios. Tienes
begins_with,between,>,<— diseña la clave para que la lectura que necesitas sea un prefijo o un rango, no unScan. - El delimitador carga peso. Elige uno que no pueda aparecer en un segmento de path, o dos ramas no relacionadas chocan.
Por qué la sort key es todo el juego
Si vienes de SQL, modelarías un árbol de carpetas con un self-join de
parent_id y lo recorrerías en recursión — una query por nivel. En DynamoDB eso
es un pie N+1 contra un almacén clave-valor que no tiene joins.
DynamoDB guarda cada item bajo una clave de partición ordenado por su sort key, en orden de bytes UTF-8 para strings (AWS: Query key conditions). Así que si tu sort key es el path, el layout físico ya coincide con el árbol. Una lectura se convierte en un scan de prefijo sobre un trozo contiguo — no en un paseo por un grafo.
Ese es el cambio: la sort key no es un identificador que matcheas exactamente. Es una dirección ordenable. Diseñala y la query sale gratis.
Modela un árbol de sistema de ficheros
Digamos que guardas árboles de ficheros por cuenta. Un drive por cuenta es la partición natural; el path dentro es la sort key.
| PK | SK | node_type | bytes |
|---|---|---|---|
| DRIVE#a91 | root/ | folder | - |
| DRIVE#a91 | root/docs/ | folder | - |
| DRIVE#a91 | root/docs/taxes.pdf | file | 88210 |
| DRIVE#a91 | root/photos/ | folder | - |
| DRIVE#a91 | root/photos/2026/ | folder | - |
| DRIVE#a91 | root/photos/2026/beach.jpg | file | 284910 |
| DRIVE#a91 | root/photos/2026/sunset.jpg | file | 512004 |
Dos convenciones originales haciendo el trabajo aquí:
PK = DRIVE#<account>mantiene el árbol entero de una cuenta en una sola , así que cualquier lectura de subárbol es unQueryde una sola partición.SKes el path completo con una/final en las carpetas. La barra final es deliberada — hace que una carpeta ordene antes que sus propios hijos y mantieneroot/photos/distinto de un fichero hermano llamadoroot/photos.
Lee un subárbol en una sola query
Lista todo bajo root/photos/ — carpeta, subcarpetas y ficheros, en recursión:
Query
KeyConditionExpression = PK = :drive AND begins_with(SK, :prefix)
:drive = "DRIVE#a91"
:prefix = "root/photos/"
Eso devuelve root/photos/, root/photos/2026/, beach.jpg y sunset.jpg —
en orden de path, en una sola lectura facturada. Solo pagas por los items de ese
trozo, no por el drive entero.
En DynoTable lanzas exactamente este Query con begins_with contra la sort
key de path y la carpeta más sus descendientes vuelven en orden de path — sin
sintaxis de placeholder que escribir a mano.
¿Necesitas el KeyConditionExpression crudo (nombres, valores y begins_with)
para tu propio código? Constrúyelo y cópialo en el
generador de expresiones de DynamoDB.

Lista un nivel, no el subárbol entero
begins_with te da la lectura recursiva. Para un listado de directorio no
recursivo — los hijos inmediatos de root/photos/ y nada más profundo — guarda
un atributo depth y añade un rango de sort key más un filtro, o parte el
path en un GSI de parent. La versión más simple: mantén un atributo parent
(root/photos/) y un GSI claveado sobre él.
Una sort key responde barato a preguntas de prefijo y rango. «Solo
hijos directos» es otra pregunta — modélala explícitamente en lugar de esperar
que un FilterExpression la haga eficiente. Un filtro corre después de la
lectura y pagas por cada item que descarta.
Elige el delimitador con cuidado
El delimitador es parte de tu contrato de datos. Dos reglas:
- Nunca debe aparecer dentro de un segmento de path. Si los nombres de
fichero pueden contener
/,/es el delimitador equivocado — un fichero llamadoa/bes indistinguible de una carpetaaque contieneb. Elige un byte reservado (algunos equipos usan#o un carácter de control) y prohíbelo en los segmentos. - Cuida el orden de sort en los límites.
/(0x2F) ordena antes que dígitos y letras, que suele ser lo que quieres para orden de árbol. Cambia el delimitador y cambias el ordenamiento — verifícalo contra datos reales.
Sort key compuesta vs. un atributo de sort aparte
Sort key compuesta (root/photos/2026/x) | Sort key ID plano + atributo parent | |
|---|---|---|
| Lectura de subárbol | Un Query con begins_with | Queries recursivas (N+1) o un paseo por GSI |
| Ordenamiento | Orden de path, gratis | Hay que añadir un atributo de sort explícito |
| Move / rename | Reescribir todos los descendientes | Actualizar un puntero parent |
| Lista de hijos directos | Necesita attr depth o GSI | Natural (parent = x) |
Las claves compuestas ganan cuando las lecturas son en forma de subárbol y el orden importa; el modelo de ID plano gana cuando el árbol muta sin parar. La mayoría de jerarquías read-heavy — árboles de ficheros, de categorías, org charts — se inclinan por la compuesta.
Escollos y próximos pasos
- No sobrecargues la clave. Todo lo que codificas es inmutable e indexado solo por prefijo. Los atributos que consultas por igualdad van en sus propios campos o en un GSI, no metidos a presión en la sort key.
- Una sort key no hace
WHEREarbitrarios. Solobegins_with,betweeny comparaciones. Si te pillas buscando unFilterExpression, probablemente modelaste la clave mal — ver Query vs. Scan. - Ir más a fondo en el diseño de claves vive en el single-table design; para cuando una lectura de subárbol necesita un índice en lugar de la tabla base, ver GSI vs. LSI.
Construye la key condition con begins_with en el
Expression Builder, luego
descarga DynoTable para lanzar estos Queries de prefijo contra tus
propias tablas y ver un subárbol volver en orden de path. (¿Y el self-JOIN que
dejaste atrás en SQL? El SQL Workbench de DynoTable
sigue ejecutándolo cuando lo necesitas.)


