Intermedio8 min de lectura

Relaciones uno a varios en DynamoDB

Un plano de control SaaS casi siempre tiene una jerarquía de contención: un espacio de trabajo posee muchos proyectos. En SQL pondrías una clave externa workspace_id en la tabla de proyectos y harías un JOIN.

DynamoDB no tiene ni joins ni claves externas, así que la relación tiene que vivir en el esquema de claves mismo. Bien hecho, "cargar un espacio de trabajo y cada proyecto dentro de él" se convierte en una única Query en lugar de una lectura más un scan de seguimiento.

¿Cómo se modela una relación uno a varios en DynamoDB?

Dale al elemento padre y a todos sus hijos la misma para que compartan una , y luego diferéncialos con la clave de ordenación. DynamoDB no tiene joins ni claves externas, así que la relación vive en el esquema de claves mismo. Cargar un padre más cada hijo se convierte entonces en una única Query en lugar de un join.

  • Modela las lecturas, no las entidades. La relación uno a varios solo existe para servir "listar los proyectos de un espacio de trabajo": da forma a las claves en torno a esa consulta.
  • Codifica el padre en la del hijo. Dale al espacio de trabajo y a todos sus proyectos el mismo valor de clave de partición para que caigan en una sola .
  • Entonces la lectura de la lista es una sola Query. El padre más sus hijos vuelven juntos: sin join, sin un segundo viaje de ida y vuelta (una Query devuelve hasta 1 MB por página, paginando mediante LastEvaluatedKey más allá de eso).
  • Vigila la . Un único inquilino enorme concentra todo su tráfico en una partición; un espacio de trabajo gigante puede necesitar una clave fragmentada y una lectura de tipo fan-out.

El patrón de acceso, primero

El modelado en DynamoDB va primero por patrón de acceso, no por entidad: la misma disciplina que hay detrás del diseño de tabla única. Antes de elegir cualquier clave, escribe las lecturas que la aplicación realmente emite:

  • Obtener la configuración de un espacio de trabajo.
  • Listar cada proyecto de un espacio de trabajo, del más reciente primero.
  • Obtener un proyecto concreto por su id.

La relación "un espacio de trabajo, muchos proyectos" solo importa por la lectura n.º 2. Si nunca necesitaras listar juntos los proyectos de un espacio de trabajo, no modelarías la relación en absoluto: almacenarías los proyectos de forma independiente.

Así que la pregunta nunca es "¿cómo represento el uno a varios?" en abstracto. Es "¿qué consultas debe servir esta relación?". Responde eso y luego da forma a las claves en torno a ello.

Por qué una clave externa no ayuda aquí

En DynamoDB cada GetItem y cada Query apuntan a una clave de partición, y el servicio hace un hash de esa clave para localizar la partición que contiene el elemento.

AWS lo dice directamente en la documentación de Componentes principales: el valor de la clave de partición es la entrada de una función hash interna que decide dónde vive el dato.

Esa colocación basada en hash es la herencia del artículo original de 2007 Dynamo: Amazon's Highly Available Key-value Store, donde el hash consistente distribuye las claves entre los nodos.

Un simple atributo workspace_id en un elemento de proyecto es invisible para esa maquinaria: DynamoDB no puede "seguirlo".

Para recuperar elementos relacionados en una sola petición, la identidad del padre debe estar codificada en la clave de partición del proyecto, de modo que todos los elementos de un espacio de trabajo hagan hash a la misma partición y una sola Query pueda barrerlos.

Ejemplo desarrollado: espacios de trabajo y proyectos

Usa un esquema de claves genérico y sobrecargado. Llama a la clave de partición EntityRef y a la clave de ordenación Detail. La identidad del espacio de trabajo va en EntityRef tanto para el elemento del espacio de trabajo como para cada proyecto bajo él:

EntityRefDetailattributes
WS#acmeMETAdisplayName, region, seatLimit
WS#acmePROJ#2026-0007title, status, createdBy
WS#acmePROJ#2026-0042title, status, createdBy
WS#acmePROJ#2026-0118title, status, createdBy
WS#globexMETAdisplayName, region, seatLimit
WS#globexPROJ#2026-0009title, status, createdBy

El espacio de trabajo y todos sus proyectos comparten EntityRef = "WS#acme", así que forman una única colección de elementos que vive junta en una partición.

La clave de ordenación Detail los separa: META es el registro del espacio de trabajo, y cada proyecto lleva un prefijo PROJ# con un id ordenado por tiempo y rellenado con ceros para que los proyectos se ordenen de forma natural.

Visualmente, el padre y sus hijos se apilan dentro de una partición, ordenados por la clave de ordenación:

Partición: EntityRef = WS#acmeMETA ajustes del espacio detrabajoPROJ#2026-0007PROJ#2026-0042PROJ#2026-0118

Una sola Query sobre EntityRef = "WS#acme" barre toda la pila —el padre más cada hijo— en una única lectura.

Ahora los tres patrones de acceso se reducen cada uno a una llamada:

  • Configuración del espacio de trabajoGetItem(EntityRef="WS#acme", Detail="META").
  • Listar proyectos del más reciente primeroQuery(EntityRef="WS#acme") con Detail begins_with "PROJ#", ejecutada en orden descendente (ScanIndexForward = false).
  • Un proyectoGetItem(EntityRef="WS#acme", Detail="PROJ#2026-0042").

La segunda es la clave de todo: el padre y sus hijos vuelven de una Query, sin join y sin un segundo viaje de ida y vuelta —DynamoDB devuelve hasta 1 MB por página y te entrega una LastEvaluatedKey para recuperar el resto—. Ese es el movimiento que no puedes hacer con un atributo de clave externa y un Scan.

Escribir esa condición begins_with a mano es delicado: la sintaxis de la condición de clave y de la expresión de proyección muerde.

El Constructor de expresiones de DynamoDB genera la KeyConditionExpression, los mapas de marcadores #name/:value y un fragmento de SDK listo para ejecutar, para que no pelees con la gramática:

KeyConditionExpression     "#er = :er AND begins_with(#d, :p)"
ExpressionAttributeNames   { "#er": "EntityRef", "#d": "Detail" }
ExpressionAttributeValues  { ":er": "WS#acme", ":p": "PROJ#" }

Inspecciona la colección de elementos en DynoTable

La recompensa de esta disposición es visual: cada fila que comparte un EntityRef es el espacio de trabajo más sus hijos, uno junto al otro.

DynoTable los agrupa para que veas la relación uno a varios como un bloque contiguo en lugar de adivinarla a través de tablas separadas.

El elemento META del espacio de trabajo y sus hijos PROJ# agrupados como una sola colección de elementos en la vista de tabla de DynoTable.
El elemento META del espacio de trabajo y sus hijos PROJ# agrupados como una sola colección de elementos en la vista de tabla de DynoTable.

Trampas y la forma alternativa

Unas cuantas cosas a vigilar:

  • Particiones activas. Cada elemento de un espacio de trabajo vive en una partición, así que un único inquilino muy grande o muy ocupado concentra el tráfico. El comportamiento de capacidad adaptativa que describe AWS absorbe un sesgo moderado, pero un espacio de trabajo con millones de proyectos puede necesitar una clave fragmentada (p. ej. WS#acme#01 … #10) y una lectura de tipo fan-out.
  • Tamaño de la colección de elementos. Con un índice secundario local, la colección de elementos de una sola partición está limitada a 10 GB; sin un LSI no hay tal límite. Si estás sopesando aquí los tipos de índice, consulta GSI vs LSI.
  • Recurre a Query, nunca a Scan. Todo el diseño existe para que puedas hacer Query sobre una partición. Recurrir a un Scan filtrado para "encontrar los proyectos de un espacio de trabajo" tira el modelo por la borda y lee la tabla entera: la trampa que se cubre en Query vs Scan.

Si realmente necesitas listar proyectos entre espacios de trabajo (digamos, todos los proyectos status = ACTIVE a nivel global), la tabla base no puede responder eso: su clave de partición está acotada al espacio de trabajo.

Ese es un trabajo para un índice secundario que reparticione los proyectos por un atributo distinto, no para remodelar esta relación.

Próximos pasos

Modela los patrones de acceso, codifica el padre en la clave de partición del hijo y la lectura uno a varios será una sola Query. Construye y valida la condición de clave con el Constructor de expresiones de DynamoDB — y si prefieres partir de los propios patrones de acceso, la herramienta de diseño de tabla única gratuita esboza el plan de PK/SK/GSI con Items de ejemplo.

Luego descarga DynoTable para cargar este esquema, explorar en vivo la colección de elementos espacio de trabajo→proyectos y confirmar que cada consulta hace exactamente una lectura. Si prefieres ver espacios de trabajo y proyectos como una vista relacional unida, el SQL Workbench de DynoTable también ejecuta ese JOIN.

Actualizado

Prueba este diseño de forma interactiva

Esboza tus entidades y patrones de acceso en la herramienta gratuita de diseño de tabla única de DynamoDB: sugiere plantillas de claves PK/SK, previsualiza las colecciones de Items y muestra qué patrones necesitan un GSI.

Abrir la herramienta de diseño de tabla única