

# Modelado de datos para tablas de DynamoDB
<a name="data-modeling"></a>

Antes de profundizar en el modelado de datos, es importante comprender algunos fundamentos de DynamoDB. DynamoDB es una base de datos NoSQL de clave-valor que permite esquemas flexibles. El conjunto de atributos de los datos, aparte de los atributos clave de cada elemento, puede ser uniforme o discreto. El esquema de claves de DynamoDB tiene la forma de una clave principal simple en la que una clave de partición identifica de forma exclusiva un elemento o la forma de una clave primaria compuesta en la que una combinación de una clave de partición y una clave de clasificación define de forma exclusiva un elemento. Se crea un hash de la clave de partición para determinar la ubicación física de los datos y recuperarlos. Por lo tanto, es importante elegir un atributo de alta cardinalidad y escalable horizontalmente como clave de partición para garantizar una distribución uniforme de los datos. El atributo de clave de clasificación es opcional en el esquema de claves y disponer de una clave de clasificación permite modelar relaciones de uno a varios y crear colecciones de elementos en DynamoDB. Además, las claves de clasificación también se denominan claves de intervalo: se utilizan para clasificar elementos de una colección de elementos y también permiten realizar operaciones flexibles basadas en intervalos.

Para obtener más detalles y las prácticas recomendadas acerca del esquema de claves de DynamoDB, puede consultar lo siguiente:
+ [Particiones y distribución de datos en DynamoDB](HowItWorks.Partitions.md) 
+ [Prácticas recomendadas para diseñar claves de partición y utilizarlas con eficacia en DynamoDB](bp-partition-key-design.md) 
+ [Prácticas recomendadas sobre el uso de claves de clasificación para organizar datos en DynamoDB](bp-sort-keys.md) 
+ [Elección de la clave de partición de DynamoDB adecuada](https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/) 

Los índices secundarios suelen ser necesarios para admitir patrones de consulta adicionales en DynamoDB. Los índices secundarios son tablas sombra en las que los mismos datos se organizan mediante un esquema de claves distinto al de la tabla base. Un índice secundario local (LSI) comparte la misma clave de partición que la tabla base y permite tener una clave de clasificación alternativa con la que puede compartir la capacidad de la tabla base. Un índice secundario global (GSI) puede tener una clave de partición y un atributo de clave de clasificación diferentes a los de la tabla base, lo que significa que la administración del rendimiento de un GSI es independiente de la tabla base.

Para obtener más detalles sobre los índices secundarios y las prácticas recomendadas, puede consultar lo siguiente:
+ [Mejora del acceso con índices secundarios en DynamoDB](SecondaryIndexes.md) 
+ [Prácticas recomendadas para utilizar índices secundarios en DynamoDB](bp-indexes.md) 

Analicemos ahora el modelado de datos un poco más. El proceso de diseñar un esquema flexible y altamente optimizado en DynamoDB, o en cualquier base de datos NoSQL, puede ser una habilidad difícil de aprender. El objetivo de este módulo es ayudarlo a desarrollar un diagrama de flujo mental para diseñar un esquema que lo lleve del caso de uso a la producción. Empezaremos con una introducción a la elección fundamental de cualquier diseño: diseño de tabla única frente a diseño de tabla múltiple. A continuación, revisaremos la multitud de patrones de diseño (componentes) que se pueden utilizar para lograr diversos resultados organizativos o de rendimiento para la aplicación. Por último, incluimos una variedad de paquetes completos de diseño de esquemas para diferentes casos de uso y sectores.

![\[Imagen que muestra la relación conceptual entre los datos, los bloques que se encuentran debajo de ellos y, a continuación, la base que se encuentra debajo de los bloques.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesign.png)


**Topics**
+ [Colecciones de elementos: cómo modelar relaciones de uno a varios en DynamoDB](WorkingWithItemCollections.md)
+ [Principios básicos del modelado de datos en DynamoDB](data-modeling-foundations.md)
+ [Componentes del modelado de datos en DynamoDB](data-modeling-blocks.md)
+ [Paquetes de diseño de esquemas de modelado de datos en DynamoDB](data-modeling-schemas.md)
+ [Prácticas recomendadas para modelar datos relacionales en DynamoDB](bp-relational-modeling.md)

# Colecciones de elementos: cómo modelar relaciones de uno a varios en DynamoDB
<a name="WorkingWithItemCollections"></a>

En DynamoDB, una *colección de elementos* es un grupo de elementos que comparten el mismo valor de clave de partición, lo que significa que los elementos están relacionados. Las colecciones de elementos son el mecanismo principal para modelar las relaciones de uno a varios en DynamoDB. Las colecciones de elementos solo pueden existir en tablas o índices configurados para utilizar una [clave primaria compuesta](HowItWorks.CoreComponents.md#HowItWorks.CoreComponents.PrimaryKey).

**nota**  
Las colecciones de elementos pueden existir en una tabla base o en un índice secundario. Para obtener más información específicamente sobre cómo interactúan las colecciones de elementos con los índices, consulte [Colecciones de elementos en los índices secundarios locales](LSI.md#LSI.ItemCollections).

Considere la siguiente tabla que muestra tres usuarios diferentes y sus inventarios en el juego:

![\[Tres colecciones de elementos diferentes con distintos atributos.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/item_collection.png)


Para algunos elementos de cada colección, la clave de clasificación es una concatenación formada por información utilizada para agrupar datos, como `inventory::armor`, `inventory::weapon` o `info`. Cada colección de elementos puede tener una combinación diferente de estos atributos como clave de clasificación. El usuario `account1234` tiene un elemento `inventory::weapons`, mientras que el usuario `account1387` no lo tiene (porque aún no ha encontrado ninguno). El usuario `account1138` solo utiliza dos elementos para su clave de clasificación (ya que aún no tiene inventario) mientras que los demás usuarios utilizan tres.

DynamoDB le permite recuperar de forma selectiva elementos de estas colecciones de elementos para hacer lo siguiente:
+ Recuperar todos los elementos de un usuario concreto
+ Recuperar solo un elemento de un usuario concreto
+ Recuperar todos los elementos de un tipo específico pertenecientes a un usuario concreto

## Acelerar las consultas mediante la organización de los datos con colecciones de elementos
<a name="WorkingWithItemCollections.Example"></a>

En este ejemplo, cada uno de los elementos de estas tres colecciones de elementos representa a un jugador y el modelo de datos que hemos elegido, basado en los patrones de acceso del juego y del jugador. ¿Qué datos necesita el juego? ¿Cuándo los necesita? ¿Con qué frecuencia los necesita? ¿Cuál es el costo de hacerlo de esta manera? Estas decisiones de modelado de datos se tomaron a partir de las respuestas a estas preguntas.

En este juego, se presenta al jugador una página diferente para su inventario para las armas y otra página para la armadura. Cuando el jugador abre su inventario, las armas se muestran primero porque deseamos que esa página se cargue muy rápida, mientras que las siguientes páginas del inventario pueden cargarse después. Como cada uno de estos tipos de elementos puede ser bastante grande a medida que el jugador adquiere más elementos en el juego, decidimos que cada página del inventario sería su propio elemento en la colección de elementos del jugador en la base de datos. 

En la siguiente sección se describe con más detalle cómo puede interactuar con las colecciones de elementos a través de la operación `Query`.

**Topics**
+ [Acelerar las consultas mediante la organización de los datos con colecciones de elementos](#WorkingWithItemCollections.Example)

# Principios básicos del modelado de datos en DynamoDB
<a name="data-modeling-foundations"></a>

En esta sección se trata la capa fundamental mediante el examen de los dos tipos de diseño de tablas: tabla única y tabla múltiple.

![\[Imagen que muestra la relación conceptual entre los datos, los bloques que se encuentran debajo de ellos y, a continuación, la base que se encuentra debajo de los bloques. Énfasis en la base.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignFoundation.png)


## Principios básicos de diseño de tabla única
<a name="data-modeling-foundations-single"></a>

Una opción para el principio básico de nuestro esquema de DynamoDB es el **diseño de tabla única**. El diseño de tabla única es un patrón que permite almacenar varios tipos (entidades) de datos en una sola tabla de DynamoDB. El objetivo es optimizar los patrones de acceso a los datos, mejorar el rendimiento y reducir los costos al eliminar la necesidad de mantener tablas múltiples y relaciones complejas entre ellas. Esto es posible porque DynamoDB almacena elementos con la misma clave de partición (lo que se conoce como recopilación de elementos) en las mismas particiones entre sí. En este diseño, los diferentes tipos de datos se almacenan como elementos en la misma tabla y cada elemento se identifica mediante una clave de clasificación única.

![\[Imagen que muestra una tabla y cómo se usa la clave de clasificación para diferenciar cada elemento por tipo de entidad dentro de la misma recopilación de elementos de UserID.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SingleTableSchema.png)


**Ventajas**
+ Localización de datos para admitir consultas para varios tipos de entidades en una sola llamada a la base de datos
+ Reduce los costos financieros y de latencia generales de las lecturas:
  + Una sola consulta para dos elementos con un total de menos de 4 KB es 0,5 RCU de coherencia eventual
  + Dos consultas para dos elementos con un total de menos de 4 KB es 1 RCU de coherencia eventual (0,5 cada RCU)
  + El tiempo para devolver dos llamadas independientes a la base de datos será, de media, superior al de una sola llamada
+ Reduce el número de tablas que hay que administrar:
  + No es necesario mantener los permisos en varios roles o políticas de IAM 
  + La administración de la capacidad de la tabla se calcula de media en todas las entidades, lo que suele dar como resultado un patrón de consumo más predecible
  + El monitoreo requiere menos alarmas
  + Las claves de cifrado administradas por el cliente solo se deben rotar en una tabla
+ Suaviza el tráfico hacia la tabla:
  + Al agregar varios patrones de uso a la misma tabla, el uso general tiende a ser más fluido (de la misma manera que el rendimiento de un índice bursátil tiende a ser más fluido que el de cualquier acción individual), lo que funciona mejor para lograr una mayor utilización con tablas de modos aprovisionadas

**Desventajas**
+ La curva de aprendizaje puede ser pronunciada debido a un diseño paradójico en comparación con las bases de datos relacionales
+ Los requisitos de datos deben ser coherentes en todos los tipos de entidades
  + Las copias de seguridad son todo o nada, por lo que si algunos datos no son de vital importancia, considere guardarlos en una tabla distinta
  + El cifrado de tablas se comparte entre todos los elementos. Para las aplicaciones de varios inquilinos con requisitos de cifrado de inquilinos individuales, se requeriría el cifrado del cliente
  + Las tablas con una combinación de datos históricos y datos operativos no obtendrán tantos beneficios al habilitar la clase de almacenamiento de acceso poco frecuente. Para obtener más información, consulte [Clases de tablas de DynamoDB](HowItWorks.TableClasses.md) 
+ Todos los datos modificados se propagarán a DynamoDB Streams aunque solo se tenga que procesar un subconjunto de entidades.
  + Gracias a los filtros de eventos de Lambda, esto no afectará a la factura cuando utilice Lambda, pero supondrá un costo adicional si utiliza la Kinesis Consumer Library 
+ Al usar GraphQL, el diseño de una sola tabla será más difícil de implementar
+ Cuando se utilizan clientes de SDK de nivel superior, como [`DynamoDBMapper`](DynamoDBMapper.md) de Java o [Cliente mejorado](DynamoDBEnhanced.md), puede resultar más difícil procesar los resultados porque los elementos de la misma respuesta pueden estar asociados a clases diferentes

**Cuándo se debe usar**

El diseño de tabla única funciona bien para aplicaciones que consultan con frecuencia varios tipos de entidades juntos o que necesitan mantener relaciones entre diferentes tipos de datos. Es especialmente eficaz cuando los patrones de acceso se benefician de la localización de los datos y cuando se desea minimizar la sobrecarga de administración de múltiples tablas.

## Principios básicos de diseño de tabla múltiple
<a name="data-modeling-foundations-multi"></a>

La segunda opción para el principio básico de nuestro esquema de DynamoDB es el diseño de tabla múltiple****. El diseño de tabla múltiple es un patrón que se parece más a un diseño de base de datos tradicional, en el que se almacena un único tipo (entidad) de datos en cada tabla de DynamoDB. Los datos de cada tabla seguirán organizados por clave de partición, por lo que el rendimiento dentro de un solo tipo de entidad se optimizará en función de la escalabilidad y el rendimiento, pero las consultas en varias tablas se deben realizar de forma independiente.

![\[Imagen que muestra una tabla de foro que contiene una lista de foros y algunos datos agregados.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/MultipleTable1.png)


![\[Imagen que muestra una tabla de hilos que contiene una lista de hilos divididos por el foro específico al que pertenecen.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/MultipleTable2.png)


**Ventajas**
+ Más fácil de diseñar para aquellos que no están acostumbrados a trabajar con un diseño de tabla única 
+ Implementación más sencilla de los solucionadores de GraphQL debido a que cada resolución se asigna a una sola entidad (tabla)
+ Permite requisitos de datos únicos en diferentes tipos de entidades:
  + Se pueden realizar copias de seguridad de las tablas individuales que son críticas 
  + El cifrado de tablas se puede administrar para cada tabla. Para las aplicaciones de múltiples inquilinos con requisitos de cifrado de inquilinos individuales, las tablas de inquilinos independientes permiten que cada cliente tenga su propia clave de cifrado
  + La clase de almacenamiento de acceso poco frecuente se puede habilitar solo en las tablas con datos históricos para obtener todos los beneficios de ahorro de costos. Para obtener más información, consulte [Clases de tablas de DynamoDB](HowItWorks.TableClasses.md)
+ Cada tabla tendrá su propio flujo de datos de cambios, lo que permitirá diseñar una función de Lambda dedicada para cada tipo de elemento, en lugar de un único procesador monolítico

**Desventajas**
+ Para los patrones de acceso que requieren datos en varias tablas, se requerirán varias lecturas de DynamoDB y es posible que sea necesario procesar o unir los datos en el código del cliente.
+ Las operaciones y el monitoreo de varias tablas requieren más alarmas de CloudWatch y cada tabla se debe escalar de forma independiente
+ Los permisos de cada tabla se deberán administrar de forma independiente. La adición de tablas en el futuro requerirá un cambio en los roles de IAM o políticas necesarios

**Cuándo se debe usar**

Si los patrones de acceso de su aplicación no tienen la necesidad de consultar varias entidades o tablas a la vez, entonces el diseño de tablas múltiples es un enfoque bueno y suficiente.

# Componentes del modelado de datos en DynamoDB
<a name="data-modeling-blocks"></a>

En esta sección se trata la capa de componentes para ofrecerle patrones de diseño que pueda utilizar en su aplicación.

![\[Imagen que muestra la relación conceptual entre los datos, los bloques que se encuentran debajo de ellos y, a continuación, la base que se encuentra debajo de los bloques. Énfasis en la base.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignBlocks.png)


**Topics**
+ [Componente de clave de clasificación compuesta](#data-modeling-blocks-composite)
+ [Complemento de tenencia múltiple](#data-modeling-blocks-multi-tenancy)
+ [Componente de índices dispersos](#data-modeling-blocks-sparse-index)
+ [Componente de tiempo de vida](#data-modeling-blocks-ttl)
+ [Componente de tiempo de vida para fines de archivado](#data-modeling-blocks-ttl-archival)
+ [Componente de particiones verticales](#data-modeling-blocks-vertical-partitioning)
+ [Escribir un componente de partición](#data-modeling-blocks-write-sharding)

## Componente de clave de clasificación compuesta
<a name="data-modeling-blocks-composite"></a>

Cuando las personas piensan en NoSQL, también pueden pensar que no es relacional. En última instancia, no hay ningún motivo para que las relaciones no puedan incluirse en un esquema de DynamoDB, simplemente tienen un aspecto diferente al de las bases de datos relacionales y las claves externas. Uno de los patrones más importantes que podemos utilizar para desarrollar una jerarquía lógica de nuestros datos en DynamoDB es una clave de clasificación compuesta. El estilo más común para diseñar una es separar cada capa de la jerarquía (capa principal > capa secundaria > capa secundaria de la secundaria) mediante un hashtag. Por ejemplo, `PARENT#CHILD#GRANDCHILD#ETC`.

![\[Imagen que muestra un elemento de una tabla con un ID de usuario como clave principal y una combinación de otros atributos como clave de clasificación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ShoppingCart.png)


Si bien una clave de partición en DynamoDB siempre requiere el valor exacto para consultar los datos, podemos aplicar una condición parcial a la clave de clasificación de izquierda a derecha, similar a recorrer un árbol binario.

En el ejemplo anterior, tenemos una tienda de e-commerce con un carro de la compra que debe mantenerse en todas las sesiones de usuario. Siempre que el usuario inicie sesión, es posible que desee ver todo el carro de la compra, incluidos los elementos guardados para más adelante. Sin embargo, cuando ingrese al proceso de compra, solo se deben cargar los elementos del carro activos para la compra. Dado que ambas `KeyConditions` solicitan explícitamente las claves de clasificación CART, DynamoDB simplemente ignora los datos adicionales de la lista de deseos durante la lectura. Aunque los elementos guardados y los activos forman parte del mismo carro, debemos tratarlos de forma diferente en las diferentes partes de la aplicación, por lo que aplicar una `KeyCondition` al prefijo de la clave de clasificación es la forma más optimizada de recuperar solo los datos necesarios para cada parte de la aplicación.

**Características claves de este componente**
+ Los elementos relacionados se almacenan localmente entre sí para un acceso efectivo a los datos 
+ Mediante expresiones `KeyCondition`, los subconjuntos de la jerarquía se pueden recuperar de forma selectiva, lo que significa que no hay RCU desperdiciadas 
+ Las diferentes partes de la aplicación pueden almacenar los elementos con un prefijo específico para evitar que se sobrescriban o se produzcan conflictos de escritura

## Complemento de tenencia múltiple
<a name="data-modeling-blocks-multi-tenancy"></a>

Muchos clientes utilizan DynamoDB para alojar datos para las aplicaciones de tenencia múltiple. Para estos casos, lo mejor es diseñar el esquema de manera que mantenga todos los datos de un único inquilino en su propia partición lógica de la tabla. Esto aprovecha el concepto de recopilación de elementos, que es un término para todos los elementos de una tabla de DynamoDB con la misma clave de partición. Para obtener más información sobre cómo DynamoDB aborda la multitenencia, consulte [Multitenencia en DynamoDB](https://docs.aws.amazon.com/whitepapers/latest/multi-tenant-saas-storage-strategies/multitenancy-on-dynamodb.html). 

![\[Imagen que muestra una tabla que podría representar un sitio de fotografías de tenencia múltiple. La clave principal se compone de usuarios como la clave de partición y diferentes fotografías como la clave de clasificación. El atributo de cada elemento muestra la URL en la que está alojada la foto.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/MultiTenant.png)


Para este ejemplo, gestionamos un sitio de alojamiento de fotos con miles de usuarios potenciales. Inicialmente, cada usuario solo cargará fotos en su propio perfil, pero de forma predeterminada no permitiremos que ningún usuario vea las fotos de ningún otro usuario. Lo ideal sería agregar un nivel adicional de aislamiento a la autorización de la llamada de cada usuario a la API para garantizar que solo soliciten datos de su propia partición, pero a nivel de esquema, son adecuadas las claves de partición únicas.

**Características clave de este componente**
+ La cantidad de datos leídos por cualquier usuario o inquilino solo puede ser igual a la cantidad total de elementos en la partición
+ La eliminación de los datos de un inquilino debido al cierre de una cuenta o a una solicitud de cumplimiento se puede hacer con tacto y de forma económica. Simplemente ejecute una consulta en la que la clave de partición sea igual al ID de inquilino y, a continuación, ejecute una operación `DeleteItem` para cada clave principal devuelta

**nota**  
Diseñado pensando en la tenencia múltiple, puede utilizar diferentes proveedores de claves de cifrado en una sola tabla para aislar los datos de forma segura. [AWS El SDK de cifrado de bases de datos](https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/what-is-database-encryption-sdk.html) para Amazon DynamoDB le permite incluir el cifrado del cliente en las cargas de trabajo de DynamoDB. Puede realizar un cifrado de nivel de atributo, lo que le permite cifrar valores de atributos específicos antes de almacenarlos en la tabla de DynamoDB y buscar atributos cifrados sin descifrar previamente toda la base de datos. 

## Componente de índices dispersos
<a name="data-modeling-blocks-sparse-index"></a>

A veces, un patrón de acceso requiere buscar objetos que coincidan con un elemento raro o un objeto que reciba un estado (lo que requiere una respuesta escalada). En lugar de consultar estos elementos con regularidad en todo el conjunto de datos, podemos aprovechar el hecho de que los **índices secundarios globales (GSI)** están escasamente cargados de datos. Esto significa que solo los elementos de la tabla base que tengan los atributos definidos en el índice se replicarán en el índice.

![\[Imagen que muestra una tabla base que recibe una gran cantidad de datos de estado estable\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SparseBaseTable.png)


![\[Imagen que muestra un índice secundario global que solo recibe elementos que se han escalado\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SparseGSI.png)


En este ejemplo, vemos un caso de uso de IOT en el que cada dispositivo del campo informa de un estado de forma regular. En la mayoría de los informes, esperamos que el dispositivo informe que todo está bien, pero en ocasiones puede haber un error y hay que remitirlo a un técnico de reparación. En el caso de los informes con una escalación, el atributo `EscalatedTo` se agrega al elemento, pero de lo contrario no está presente. El GSI de este ejemplo está particionado por `EscalatedTo` y, dado que el GSI trae las claves de la tabla base, aún podemos ver qué DeviceID informó del error y en qué momento.

Aunque las lecturas son más baratas que las escrituras en DynamoDB, los índices dispersos son una herramienta muy eficaz para casos de uso en los que las instancias de un tipo específico de elemento son poco frecuentes, pero son habituales las lecturas para encontrarlos.

**Características claves de este componente**
+ Los costos de escritura y almacenamiento del GSI disperso solo se aplican a los elementos que coinciden con el patrón de claves, por lo que el costo del GSI puede ser sustancialmente menor que el de otros GSI en los que se replican todos los elementos 
+ Todavía se puede utilizar una clave de clasificación compuesta para reducir aún más los elementos que coinciden con la consulta deseada; por ejemplo, se puede usar una marca temporal para que la clave de clasificación solo vea los errores notificados en los últimos X minutos (`SK > 5 minutes ago, ScanIndexForward: False`)

## Componente de tiempo de vida
<a name="data-modeling-blocks-ttl"></a>

La mayoría de los datos tienen un periodo de tiempo durante el cual se puede considerar que vale la pena guardarlos en un almacén de datos principal. Para facilitar la salida de datos de DynamoDB, cuenta con una característica denominada **Tiempo de vida (TTL)**. La característica [TTL](TTL.md) permite definir un atributo específico en el nivel de tabla que necesita monitoreo para los elementos con una marca temporal Epoch (que está en el pasado). Esto le permite eliminar los registros caducados de la tabla de forma gratuita.

**nota**  
Si usas la [versión 2019.11.21 (actual) de las tablas globales](GlobalTables.md) y también la característica [Tiempo de vida](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html), DynamoDB replicará las eliminaciones de TTL en todas las tablas de réplica. La eliminación de TTL inicial no consume capacidad de escritura en la región donde se produce el vencimiento de TTL. Sin embargo, la eliminación de TTL replicada en las tablas de réplica consume capacidad de escritura replicada en cada una de las regiones de réplica. En estos casos, se aplicarán los cargos pertinentes.

![\[Imagen que muestra una tabla con los mensajes de un usuario con un atributo de tiempo de vida\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/TTL.png)


En este ejemplo, tenemos una aplicación diseñada para permitir a un usuario crear mensajes de corta duración. Cuando se crea un mensaje en DynamoDB, el código de la aplicación establece el atributo TTL como una fecha dentro de siete días. En aproximadamente siete días, DynamoDB comprobará que la marca temporal Epoch de estos elementos pertenece al pasado y los eliminará.

Dado que las eliminaciones realizadas por TTL son gratuitas, se recomienda encarecidamente utilizar esta característica para eliminar los datos históricos de la tabla. Esto reducirá la factura total de almacenamiento cada mes y probablemente reducirá los costos de lectura de los usuarios, ya que las consultas tendrán que recuperar menos datos. Aunque TTL está activado en el nivel de tabla, usted decide para qué elementos o entidades desea crear un atributo de TTL y en qué plazo establecer la marca temporal Epoch.

**Características clave de este componente**
+ Las eliminaciones de TTL se ejecutan entre bastidores sin afectar al rendimiento de la tabla 
+ TTL es un proceso asíncrono que se ejecuta aproximadamente cada seis horas, pero puede tardar más de 48 horas en eliminarse un registro caducado 
  + No confíe en las eliminaciones de TTL para casos de uso, como bloquear registros o administrar estados, si los datos obsoletos se deben limpiar en menos de 48 horas 
+ Puede asignar al atributo de TTL un nombre de atributo válido, pero el valor debe ser de tipo numérico

## Componente de tiempo de vida para fines de archivado
<a name="data-modeling-blocks-ttl-archival"></a>

Aunque TTL es una herramienta eficaz para eliminar datos antiguos de DynamoDB, en muchos casos de uso es necesario archivar los datos durante un periodo de tiempo mayor que el almacén de datos principal. En esta instancia, podemos aprovechar la eliminación cronometrada de registros de TTL para enviar los registros caducados a un almacén de datos a largo plazo.

![\[Imagen que muestra una tabla que envía un trabajo de eliminación de tiempo de vida a DynamoDB Streams seguido de un almacén de datos a largo plazo.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/TTLArchive.png)


Cuando DynamoDB elimina un TTL, se sigue introduciendo en DynamoDB Stream como un evento `Delete`. Cuando DynamoDB TTL es quien realiza la eliminación, hay un atributo en el registro de transmisión de `principal:dynamodb`. Al utilizar un suscriptor de Lambda a DynamoDB Stream, podemos aplicar un filtro de eventos solo para el atributo de la entidad principal de DynamoDB y saber que todos los registros que coincidan con ese filtro se enviarán a un almacén de archivos como Amazon Glacier.

**Características clave de este componente**
+  Una vez que las lecturas de baja latencia de DynamoDB ya no sean necesarias para los elementos históricos, migrarlos a un servicio de almacenamiento más frío, como Amazon Glacier, puede reducir significativamente los costos de almacenamiento y, al mismo tiempo, cumplir con los requisitos de cumplimiento de datos del caso de uso 
+ Si los datos se almacenan en Amazon S3, se pueden utilizar herramientas de análisis rentables como Amazon Athena o Redshift Spectrum para realizar un análisis histórico de los datos

## Componente de particiones verticales
<a name="data-modeling-blocks-vertical-partitioning"></a>

Los usuarios familiarizados con una base de datos de modelos de documentos estarán familiarizados con la idea de almacenar todos los datos relacionados en un único documento JSON. Aunque DynamoDB admite tipos de datos de JSON, no se permite ejecutar `KeyConditions` en JSON anidados. Dado que `KeyConditions` son las que dictan la cantidad de datos que se leen del disco y el número efectivo de RCU que consume una consulta, esto puede generar ineficiencias a escala. Para optimizar mejor las escrituras y lecturas de DynamoDB, recomendamos dividir las entidades individuales del documento en elementos individuales de DynamoDB, también denominados **particiones verticales**.

![\[Imagen que muestra una estructura de datos formateada grande con formato de objeto JSON anidado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DocumentBlob.png)


![\[Imagen que muestra una colección de elementos en la que la clave de clasificación del elemento ayuda a mantener el uso de DynamoDB optimizado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SingleTableSchema.png)


La partición vertical, como se muestra arriba, es un ejemplo clave del diseño de una sola tabla en acción, pero también se puede implementar en varias tablas si se desea. Dado que las facturas de DynamoDB se escriben en incrementos de 1 KB, lo ideal sería particionar el documento de forma que los elementos no superen 1 KB.

**Características clave de este componente**
+ Se mantiene una jerarquía de relaciones de datos mediante prefijos de clave de clasificación, por lo que la estructura del documento singular podría reconstruirse del lado del cliente si fuera necesario 
+ Los componentes singulares de la estructura de datos se pueden actualizar de forma independiente, lo que hace que las actualizaciones de elementos pequeños sean solo 1 WCU 
+ Al usar la clave de clasificación `BeginsWith`, la aplicación puede recuperar datos similares en una sola consulta, agregando los costos de lectura para reducir el costo total o la latencia
+ Los documentos grandes pueden superar fácilmente el límite de tamaño de elemento individual de 400 KB en DynamoDB y la partición vertical ayuda a evitar este límite

## Escribir un componente de partición
<a name="data-modeling-blocks-write-sharding"></a>

Uno de los pocos límites estrictos que tiene DynamoDB es la restricción del rendimiento que puede mantener una sola partición física por segundo (no necesariamente una clave de partición única). Estos límites son actualmente:
+ 1000 WCU (o 1000 elementos de <= 1 KB escritos por segundo) y 3000 RCU (o 3000 lecturas de <= 4 KB por segundo) *de coherencia alta* o 
+ 6000 lecturas de <= 4 KB por segundo *de coherencia final*

En caso de que las solicitudes de la tabla superen alguno de estos límites, se devuelve un error al SDK del cliente de `ThroughputExceededException`, más comúnmente denominado limitación. Los casos de uso que requieran operaciones de lectura más allá de ese límite se solucionarán mejor si se coloca una memoria caché de lectura delante de DynamoDB, pero las operaciones de escritura requieren un diseño en el nivel de esquema conocido como **fragmentación de escritura**.

![\[Imagen que muestra cómo DynamoDB fragmenta las claves de partición en varias particiones para evitar limitaciones de picos de tráfico.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/WriteShardingProblem.png)


![\[Imagen que muestra cómo DynamoDB fragmenta las claves de partición en varias particiones para evitar limitaciones de picos de tráfico.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/WriteShardingSolution.png)


Para resolver este problema, agregaremos un número entero aleatorio al final de la clave de partición para cada participante en el código `UpdateItem` de la aplicación. El rango del generador de enteros aleatorios deberá tener un límite superior que coincida o supere la cantidad esperada de escrituras por segundo para un participante determinado dividida entre 1000. Para respaldar 20 000 votos por segundo, se vería como rand (0,19). Ahora que los datos se almacenan en particiones lógicas independientes, deben volver a combinarse en el momento de la lectura. Como los totales de votos no tienen por qué estar en tiempo real, una función de Lambda programada para leer todas las particiones de votos cada X minutos podría realizar una agregación ocasional para cada participante y volver a escribirla en un único registro total de votos para su lectura en directo.

**Características clave de este componente**
+ Para casos de uso con un rendimiento de escritura extremadamente alto para una clave de partición determinada que no se pueda evitar, las operaciones de escritura se pueden distribuir artificialmente en varias particiones de DynamoDB 
+ Los GSI con una clave de partición de baja cardinalidad también deberían utilizar este patrón, ya que la limitación de un GSI aplicará una contrapresión a las operaciones de escritura en la tabla base

# Paquetes de diseño de esquemas de modelado de datos en DynamoDB
<a name="data-modeling-schemas"></a>

Obtenga información sobre los paquetes de diseño de esquema de modelado de datos para DynamoDB, que incluyen casos de uso, patrones de acceso y diseños de esquema finales para redes sociales, perfiles de juegos, administración de reclamaciones, pagos periódicos, estado de dispositivo y tiendas en línea.

![\[Imagen que muestra la relación conceptual entre los datos, los bloques que se encuentran debajo de ellos y, a continuación, la base que se encuentra debajo de los bloques. Énfasis en la base.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SchemaDesignData.png)


## Requisitos previos
<a name="data-modeling-prereqs"></a>

Antes de intentar diseñar nuestro esquema para DynamoDB, primero debemos recopilar algunos datos de requisitos previos sobre el caso de uso que debe admitir el esquema. A diferencia de las bases de datos relacionales, DynamoDB se fragmenta de forma predeterminada, lo que significa que los datos se alojarán en varios servidores entre bastidores, por lo que es importante diseñar teniendo en cuenta la ubicación de los datos. Tendremos que agrupar la siguiente lista para cada diseño de esquema:
+ Lista de entidades (diagrama de ER)
+ Volúmenes y rendimiento estimados para cada entidad
+ Patrones de acceso que se deben admitir (consultas y escrituras)
+ Requisitos de retención de datos

**Topics**
+ [Requisitos previos](#data-modeling-prereqs)
+ [Diseño de esquemas de redes sociales en DynamoDB](data-modeling-schema-social-network.md)
+ [Diseño de esquemas de perfiles de juego en DynamoDB](data-modeling-schema-gaming-profile.md)
+ [Diseño del esquema del sistema de administración de reclamaciones en DynamoDB](data-modeling-complaint-management.md)
+ [Diseño del esquema de pagos periódicos en DynamoDB](data-modeling-schema-recurring-payments.md)
+ [Monitoreo de las actualizaciones de estado de los dispositivos en DynamoDB](data-modeling-device-status.md)
+ [Uso de DynamoDB como almacén de datos para una tienda en línea](data-modeling-online-shop.md)

# Diseño de esquemas de redes sociales en DynamoDB
<a name="data-modeling-schema-social-network"></a>

## Caso de uso empresarial de redes sociales
<a name="data-modeling-schema-social-network-use-case"></a>

En este caso de uso se habla del uso de DynamoDB como red social. Una red social es un servicio en línea que permite a diferentes usuarios interactuar entre sí. La red social que diseñaremos permitirá al usuario ver una cronología compuesta por las publicaciones, los seguidores, a quién sigue y las publicaciones escritas por las personas a las que sigue. Los patrones de acceso para este diseño de esquema son:
+ Obtener información de usuario para un ID de usuario determinado 
+ Obtener la lista de seguidores de un ID de usuario determinado
+ Obtener la siguiente lista de un ID de usuario determinado
+ Obtener la lista de publicaciones de un ID de usuario determinado
+ Obtener una lista de usuarios a los que les gusta la publicación de un ID de publicación determinada
+ Obtener el recuento de “me gusta” para un ID de publicación determinado
+ Obtener la cronología de un ID de usuario determinado

## Diagrama de relaciones entre entidades de redes sociales
<a name="data-modeling-schema-social-network-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para el diseño del esquema de redes sociales.

![\[ERD para una aplicación de red social que muestra entidades, como Usuario, Publicación y Seguidor.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetworkERD.png)


## Patrones de acceso de redes sociales
<a name="data-modeling-schema-social-network-access-patterns"></a>

Estos son los patrones de acceso que consideraremos para el diseño del esquema de redes sociales.
+ `getUserInfoByUserID`
+ `getFollowerListByUserID`
+ `getFollowingListByUserID`
+ `getPostListByUserID`
+ `getUserLikesByPostID`
+ `getLikeCountByPostID`
+ `getTimelineByUserID`

## Evolución del diseño de esquemas de redes sociales
<a name="data-modeling-schema-social-network-design-evolution"></a>

DynamoDB es una base de datos NoSQL, por lo que no permite realizar una unión, una operación que combina datos de varias bases de datos. Es posible que los clientes que no estén familiarizados con DynamoDB apliquen filosofías de diseño del sistema de administración de bases de datos relacionales (RDBMS) (como crear una tabla para cada entidad) a DynamoDB cuando no lo necesiten. El propósito del diseño de tabla única de DynamoDB es escribir los datos en un formulario previamente unido de acuerdo con el patrón de acceso de la aplicación y, a continuación, utilizarlos inmediatamente sin cálculos adicionales. Para obtener más información, consulte [Diseño de tabla única frente a múltiples tablas en DynamoDB](https://aws.amazon.com/blogs/database/single-table-vs-multi-table-design-in-amazon-dynamodb/). 

Ahora, vamos a ver cómo evolucionaremos nuestro diseño de esquema para abordar todos los patrones de acceso.

**Paso 1: Abordar el patrón de acceso 1 (`getUserInfoByUserID`)**

Para obtener la información de un usuario determinado, necesitaremos realizar una operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html) en la tabla base con una condición clave de `PK=<userID>`. La operación de consulta le permite paginar los resultados, lo que puede ser útil cuando un usuario tiene muchos seguidores. Para obtener más información acerca de Query, consulte [Consulta de tablas en DynamoDB](Query.md). 

En nuestro ejemplo, realizamos un seguimiento de dos tipos de datos para nuestro usuario: el “recuento” y la “información”. El “recuento” de un usuario refleja cuántos seguidores tiene, cuántos usuarios sigue y cuántas publicaciones ha creado. La “información” de un usuario refleja su información personal, como su nombre.

Vemos estos dos tipos de datos representados por los dos elementos siguientes. El elemento que tiene “recuento” en su clave de clasificación (SK) tiene más probabilidades de cambiar que el elemento con “información”. DynamoDB considera el tamaño del elemento tal como aparece antes y después de la actualización y el rendimiento aprovisionado consumido reflejará el mayor de estos tamaños de elemento. Aunque se actualice tan solo un subconjunto de atributos del elemento, [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) consumirá la cantidad total de rendimiento provisionado (el mayor de los tamaños de elemento de antes y después). Puede obtener los elementos mediante una sola operación `Query` y usar `UpdateItem` para agregar o restar atributos numéricos existentes.

![\[Resultado de la operación de consulta para un usuario con ID u#12345 y los datos de recuento e información.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork1.png)


**Paso 2: Abordar el patrón de acceso 2 (`getFollowerListByUserID`)**

Para obtener una lista de los usuarios que siguen a un usuario determinado, necesitaremos `Query` la tabla base con una condición de clave de `PK=<userID>#follower`. 

![\[Resultado de la operación de consulta en una tabla para mostrar los seguidores del usuario con el ID u#12345.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork2.png)


**Paso 3: Abordar el patrón de acceso 3 (`getFollowingListByUserID`)**

Para obtener una lista de los usuarios que sigue un usuario determinado, necesitaremos `Query` la tabla base con una condición de clave de `PK=<userID>#following`. A continuación, puede utilizar una operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) para agrupar varias solicitudes y hacer lo siguiente:
+ Agregue el usuario A a la lista de seguidores del usuario B y, a continuación, incremente el número de seguidores del usuario B en uno.
+ Agregue el usuario B a la lista de seguidores del usuario A y, a continuación, incremente el número de seguidores del usuario A en uno.

![\[Resultado de la operación de consulta en una tabla para mostrar todos los seguidores del usuario con el ID u#12345.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork3.png)


**Paso 4: Abordar el patrón de acceso 4 (`getPostListByUserID`)**

Para obtener una lista de las publicaciones creadas por un usuario determinado, necesitaremos `Query` la tabla base con una condición de clave de `PK=<userID>#post`. Una cosa importante a tener en cuenta es que los ID de publicación de un usuario deben ser incrementales: el segundo valor del ID de publicación debe ser mayor que el primer valor del ID de publicación (ya que los usuarios desean ver las publicaciones de forma ordenada). Para ello, puede generar ID de publicación en función de un valor temporal, como un identificador ordenable lexicográficamente único y universal (ULID).

![\[Resultado de una operación de consulta con una condición clave para obtener una lista de publicaciones creadas por un usuario específico.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork4.png)


**Paso 5: Abordar el patrón de acceso 5 (`getUserLikesByPostID`)**

Para obtener una lista de los usuarios a los que les gusta una publicación de un usuario determinado, necesitaremos `Query` la tabla base con una condición de clave de `PK=<postID>#likelist`. Este enfoque es el mismo patrón que utilizamos para recuperar el seguidor y las listas de seguidores en el patrón de acceso 2 (`getFollowerListByUserID`) y el patrón de acceso 3 (`getFollowingListByUserID`).

![\[Resultado de una operación de consulta con una condición clave para obtener una lista de los usuarios a los que les gustó una publicación específica de un usuario.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork5.png)


**Paso 6: Abordar el patrón de acceso 6 (`getLikeCountByPostID`)**

Para obtener un recuento de los “me gusta” de una publicación determinada, tendremos que realizar una operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) en la tabla base con una condición clave de `PK=<postID>#likecount`. Este patrón de acceso puede provocar problemas de limitación cuando un usuario con muchos seguidores (como una celebridad) crea una publicación, ya que la limitación se produce cuando el rendimiento de una partición supera los 1000 WCU por segundo. Este problema no se debe a DynamoDB, solo aparece en DynamoDB, ya que se encuentra al final de la pila de software.

Debe evaluar si es realmente esencial que todos los usuarios vean el recuento de me gusta simultáneamente o si se puede producir de forma gradual con el tiempo. En general, el recuento de “me gusta” de una publicación no necesita ser inmediatamente preciso al 100 %. Puede implementar esta estrategia poniendo una cola entre la aplicación y DynamoDB para que las actualizaciones se realicen periódicamente.

![\[Resultado de la operación GetItem con una condición clave para obtener un recuento de los "me gusta" de una publicación específica.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork6.png)


**Paso 7: Abordar el patrón de acceso 7 (`getTimelineByUserID`)**

Para obtener la cronología de un usuario determinado, necesitaremos realizar una operación `Query` en la tabla base con una condición de clave de `PK=<userID>#timeline`. Vamos a tener en cuenta un escenario en el que los seguidores de un usuario necesitan ver su publicación de forma sincrónica. Cada vez que un usuario escribe una publicación, se lee su lista de seguidores y el ID de usuario e ID de publicación se ingresan lentamente en la clave de la cronología de todos sus seguidores. A continuación, cuando se inicie la aplicación, podrá leer la clave de cronología con la operación `Query` y llenar la pantalla de la cronología con una combinación de ID de usuario e ID de publicación mediante la operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html) para cualquier elemento nuevo. No puede leer la cronología con una llamada a la API, pero esta es una solución más rentable si las publicaciones se pueden editar con frecuencia.

La cronología es donde se muestran las publicaciones recientes, por lo que necesitaremos una forma de limpiar las antiguas. En lugar de utilizar WCU para eliminarlas, puede utilizar la característica [TTL](TTL.md) de DynamoDB para hacerlo de forma gratuita.

![\[Resultado de una operación de consulta con una condición clave para obtener la cronología de un usuario determinado que muestra las publicaciones recientes.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork7.png)


En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | Otras condiciones/filtros | 
| --- | --- | --- | --- | --- | --- | 
| getUserInfoByUserID | Tabla de base | Consultar | PK=<userID> |  |  | 
| getFollowerListByUserID | Tabla de base | Consultar | PK=<userID>\$1follower |  |  | 
| getFollowingListByUserID | Tabla de base | Consultar | PK=<userID>\$1following |  |  | 
| getPostListByUserID | Tabla de base | Consultar | PK=<userID>\$1post |  |  | 
| getUserLikesByPostID | Tabla de base | Consultar | PK=<postID>\$1likelist |  |  | 
| getLikeCountByPostID | Tabla de base | GetItem | PK=<postID>\$1likecount |  |  | 
| getTimelineByUserID | Tabla de base | Consultar | PK=<userID>\$1timeline |  |  | 

## Esquema final de red social
<a name="data-modeling-schema-social-network-final-schema"></a>

Este es el diseño final del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte los [ejemplos de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/SocialNetwork/SocialNetworkSchema.json) en GitHub.

**Tabla base:**

![\[Diseño de esquema final de una tabla que contiene los resultados de las operaciones Consulta y GetItem anteriores.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/SocialNetwork8.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-social-network-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Diseño de esquemas de perfiles de juego en DynamoDB
<a name="data-modeling-schema-gaming-profile"></a>

## Caso de uso empresarial del perfil de juego
<a name="data-modeling-schema-gaming-profile-use-case"></a>

En este caso de uso se habla del uso de DynamoDB para almacenar los perfiles de los jugadores de un sistema de juego. Los usuarios (en este caso, los jugadores) necesitan crear perfiles antes de poder interactuar con muchos juegos modernos, especialmente los que son en línea. Los perfiles de juego suelen incluir lo siguiente:
+ Información básica, como el nombre de usuario
+ Datos del juego, como elementos y equipos
+ Registros de juegos, como tareas y actividades
+ Información social, como listas de amigos

Para cumplir con los requisitos detallados de acceso a las consultas de datos para esta aplicación, las claves principales (clave de partición y clave de clasificación) utilizarán nombres genéricos (PK y SK) para sobrecargarlas con varios tipos de valores, como veremos a continuación.

Los patrones de acceso para este diseño de esquema son:
+ Obtener la lista de amigos de un usuario
+ Obtener toda la información de un jugador
+ Obtener la lista de elementos de un usuario
+ Obtener un elemento específico de la lista de elementos del usuario
+ Actualizar el personaje de un usuario
+ Actualizar el recuento de elementos de un usuario

El tamaño del perfil de juego variará en los diferentes juegos. Si los [valores de atributo grandes se comprimen](bp-use-s3-too.md), es posible que se ajusten a los límites de los elementos de DynamoDB y se reduzcan los costos. La estrategia de gestión del rendimiento dependería de varios factores, como el número de jugadores, el número de partidos jugados por segundo y la estacionalidad de la carga de trabajo. Normalmente, en el caso de un juego recién lanzado, se desconoce el número de jugadores y el nivel de popularidad, por lo que empezaremos con el [modo de rendimiento bajo demanda](capacity-mode.md#capacity-mode-on-demand).

## Diagrama de relación entre entidades del perfil de juego
<a name="data-modeling-schema-gaming-profile-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para el diseño del esquema del perfil de juego.

![\[Diagrama de ER para un perfil de juego, que muestra las relaciones entre entidades, como el usuario, el juego y la puntuación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfileERD.png)


## Patrones de acceso a los perfiles de juego
<a name="data-modeling-schema-gaming-profile-access-patterns"></a>

Estos son los patrones de acceso que consideraremos para el diseño del esquema de redes sociales.
+ `getPlayerFriends`
+ `getPlayerAllProfile`
+ `getPlayerAllItems`
+ `getPlayerSpecificItem`
+ `updateCharacterAttributes`
+ `updateItemCount`

## Evolución del diseño del esquema de perfiles de juego
<a name="data-modeling-schema-social-network-design-evolution"></a>

En el ERD anterior, podemos ver que este es un tipo de modelado de datos de relación de uno a varios. En DynamoDB, los modelos de datos de uno a varios se pueden organizar en recopilaciones de elementos, lo que es diferente de las bases de datos relacionales tradicionales, en las que se crean varias tablas y se vinculan mediante claves externas. Una [recopilación de elementos](WorkingWithItemCollections.md) es un grupo de elementos que comparten el mismo valor de clave de partición, pero tienen valores de clave de clasificación diferentes. Dentro de una recopilación de elementos, cada elemento tiene un valor de clave de clasificación único que lo distingue de otros elementos. Con esto en mente, vamos a usar el siguiente patrón para los valores `HASH` y `RANGE` para cada tipo de entidad.

Para empezar, utilizamos nombres genéricos como `PK` y `SK` para almacenar diferentes tipos de entidades en la misma tabla a fin de preparar el modelo para el futuro. Para una mejor legibilidad, podemos incluir prefijos para indicar el tipo de datos o incluir un atributo arbitrario llamado `Entity_type` o `Type`. En el ejemplo actual, utilizamos una cadena que comienza con `player` para almacenar `player_ID` como `PK`; usar `entity name#` como prefijo de `SK` y añadir un  atributo `Type` para indicar de qué tipo de entidad es este dato. Esto nos permitirá almacenar más tipos de entidades en el futuro y utilizar tecnologías avanzadas como sobrecarga de GSI y GSI disperso para cumplir con más patrones de acceso.

Empecemos a implementar los patrones de acceso. Los patrones de acceso, como agregar jugadores y agregar equipo, se pueden realizar a través de la operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html), por lo que podemos ignorarlos. En este documento, nos centraremos en los patrones de acceso típicos mostrados anteriormente.

**Paso 1: Abordar el patrón de acceso 1 (`getPlayerFriends`)**

Abordamos el patrón de acceso 1 (`getPlayerFriends`) con este paso. En nuestro diseño actual, la amistad es simple y el número de amigos en el juego es pequeño. Para simplificar, utilizamos un tipo de datos de lista para almacenar las listas de amigos (modelo 1:1). En este diseño, utilizamos [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) para satisfacer este patrón de acceso. En la operación `GetItem`, proporcionamos explícitamente la clave de partición y el valor de la clave de clasificación para obtener un elemento específico.

Sin embargo, si un juego tiene un gran número de amigos y las relaciones entre ellos son complejas (por ejemplo, las amistades son bidireccionales con un componente de invitación y de aceptación), sería necesario utilizar una relación de varios a varios para almacenar a cada amigo de forma individual, a fin de escalar hasta un tamaño ilimitado de la lista de amigos. Y si el cambio de amistad implica operar con varios elementos al mismo tiempo, las transacciones de DynamoDB se pueden usar para agrupar varias acciones y enviarlas como una sola operación de todo o nada [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html) o [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html).

![\[Diagrama de relaciones de varios a varios complejo para un perfil de juego de la entidad Amigos.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile1.png)


**Paso 2: Abordar los patrones de acceso 2 (`getPlayerAllProfile`), 3 (`getPlayerAllItems`) y 4 (`getPlayerSpecificItem`)**

Mediante este paso, abordamos los patrones de acceso 2 (`getPlayerAllProfile`), 3 (`getPlayerAllItems`) y 4 (`getPlayerSpecificItem`). Lo que estos tres patrones de acceso tienen en común es una consulta de rango, que utiliza la operación [`Query`](Query.md). En función del alcance de la consulta, se utilizan [Claves de condición](Query.KeyConditionExpressions.md) y [Expresiones de filtro](Query.FilterExpression.md), que se utilizan normalmente en el desarrollo práctico.

En la operación Query, proporcionamos un valor único para la clave de partición y obtenemos todos los elementos con ese valor de clave de partición. El patrón de acceso 2 (`getPlayerAllProfile`) se implementa de esta manera. De forma opcional, podemos agregar una expresión de condición de clave de clasificación, una cadena que determina los elementos que se van a leer de la tabla. El patrón de acceso 3 (`getPlayerAllItems`) se implementa al agregar la condición clave de clave de clasificación begins\$1with `ITEMS#`. Además, para simplificar el desarrollo del lado de la aplicación, podemos usar expresiones de filtro para implementar el patrón de acceso 4 (`getPlayerSpecificItem`).

Este es un ejemplo de pseudocódigo que utiliza una expresión de filtro que filtra los elementos de la categoría `Weapon`:

```
filterExpression: "ItemType = :itemType"
expressionAttributeValues: {":itemType": "Weapon"}
```

![\[El uso de la operación de consulta con una clave de partición y clave de clasificación permite implementar diferentes patrones de acceso.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile2.png)


**nota**  
Una expresión de filtro se aplica después de que Query finalice, pero antes de devolver los resultados al cliente. Por consiguiente, una Query consume la misma cantidad de capacidad de lectura aunque se especifique una expresión de filtro.

Si el patrón de acceso consiste en consultar un conjunto de datos grande y filtrar una gran cantidad de datos para conservar solo un pequeño subconjunto de datos, el enfoque adecuado consiste en diseñar la clave de partición y la clave de clasificación de DynamoDB de forma más eficaz. Por ejemplo, en el ejemplo anterior para obtener un determinado `ItemType`, si hay muchos elementos para cada jugador y la consulta de un determinado `ItemType` es un patrón de acceso típico, sería más eficiente incluir `ItemType` en `SK` como una clave compuesta. El modelo de datos tendría este aspecto: `ITEMS#ItemType#ItemId`.

**Paso 3: Abordar patrones de acceso 5 (`updateCharacterAttributes`) y 6 (`updateItemCount`)**

Mediante este paso, abordamos los patrones de acceso 5 (`updateCharacterAttributes`) y 6 (`updateItemCount`). Cuando el jugador necesite modificar el personaje, por ejemplo, reducir la moneda o modificar la cantidad de un arma determinada en los elementos, use [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) para implementar estos patrones de acceso. Para actualizar la moneda de un jugador y asegurarnos de que nunca baje de la cantidad mínima, podemos agregar una [Ejemplo de la CLI de expresión de condición de DynamoDB](Expressions.ConditionExpressions.md) para reducir el saldo solo si es superior o igual a la cantidad mínima. Este es un ejemplo de pseudocódigo:

```
UpdateExpression: "SET currency = currency - :amount"
ConditionExpression: "currency >= :minAmount"
```

![\[Uso de UpdateItem con una expresión de condición para modificar la moneda de un jugador y garantizar que nunca sea inferior a una cantidad determinada.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile4-Update-player-Currency.png)


Al desarrollar con DynamoDB y utilizar [Contadores atómicos](WorkingWithItems.md#WorkingWithItems.AtomicCounters) para reducir el inventario, podemos garantizar la idempotencia mediante el uso de un bloqueo positivo. Este es un ejemplo de pseudocódigo para contadores atómicos:

```
UpdateExpression: "SET ItemCount = ItemCount - :incr"
expression-attribute-values: '{":incr":{"N":"1"}}'
```

![\[Uso de un contador atómico para reducir el valor del atributo ItemCount de 5 a 4.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile5-Update-Item-Count.png)


Además, en un escenario en el que el jugador compra un elemento con moneda, todo el proceso debe deducir la moneda y agregar un elemento al mismo tiempo. Podemos usar las transacciones de DynamoDB para agrupar varias acciones y enviarlas como una sola operación de todo o nada `TransactWriteItems` o `TransactGetItems`. `TransactWriteItems` es una operación de escritura sincrónica e idempotente que agrupa hasta 100 acciones de escritura en una sola operación de todo o nada. Las acciones se realizan atómicamente, de tal forma que se llevan a cabo correctamente todas o ninguna de ellas. Las transacciones ayudan a eliminar el riesgo de duplicación o desaparición de divisas. Para obtener más información acerca de las transacciones, consulte [Ejemplo de transacciones en DynamoDB](transaction-example.md).

En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | Otras condiciones/filtros | 
| --- | --- | --- | --- | --- | --- | 
| getPlayerFriends | Tabla de base | GetItem | PK=PlayerID | SK=“FRIENDS\$1playerID” |  | 
| getPlayerAllProfile | Tabla de base | Consultar | PK=PlayerID |  |  | 
| getPlayerAllItems | Tabla de base | Consultar | PK=PlayerID | SK begins\$1with “ITEMS\$1” |  | 
| getPlayerSpecificItem | Tabla de base | Consultar | PK=PlayerID | SK begins\$1with “ITEMS\$1” | filterExpression: "ItemType = :itemType" expressionAttributeValues: \$1 ":itemType": "Weapon" \$1 | 
| updateCharacterAttributes | Tabla de base | UpdateItem | PK=PlayerID | SK=“\$1METADATA\$1playerID” | UpdateExpression: "SET currency = currency - :amount" ConditionExpression: "currency >= :minAmount" | 
| updateItemCount | Tabla de base | UpdateItem | PK=PlayerID | SK =“ITEMS\$1ItemID” | update-expression: "SET ItemCount = ItemCount - :incr" expression-attribute-values: '\$1":incr":\$1"N":"1"\$1\$1'  | 

## Esquema final del perfil de juego
<a name="data-modeling-schema-gaming-profile-final-schema"></a>

Este es el diseño final del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte los [ejemplos de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/GamingPlayerProfiles/GamePlayerProfilesSchema.json) en GitHub.

**Tabla base:**

![\[Diseño del esquema final de una tabla que contiene los resultados de las implementaciones de patrones de acceso anteriores.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/GamingProfile6-FinalSchema.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-gaming-profile-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Diseño del esquema del sistema de administración de reclamaciones en DynamoDB
<a name="data-modeling-complaint-management"></a>

## Caso de uso empresarial del sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-use-case"></a>

DynamoDB es una base de datos muy adecuada para el caso de uso de un sistema de administración de reclamaciones (o un centro de contacto), ya que la mayoría de los patrones de acceso asociados a ellos serían búsquedas transaccionales basadas en clave-valor. Los patrones de acceso típicos en este escenario serían:
+ Crear y actualizar reclamaciones
+ Escalar una reclamación
+ Crear y leer comentarios sobre una reclamación
+ Obtener todas las reclamaciones de un cliente
+ Obtener todos los comentarios de un agente y obtener todos los escalados 

Algunos comentarios pueden llevar asociada una descripción de la reclamación o de la solución. Aunque todos estos son patrones de acceso de clave-valor, puede haber requisitos adicionales como el envío de notificaciones cuando se agrega un nuevo comentario a una reclamación o la ejecución de consultas analíticas para hallar la distribución de reclamaciones por gravedad (o el rendimiento de los agentes) por semana. Un requisito adicional relacionado con la administración del ciclo de vida o el cumplimiento de la normativa sería archivar los datos de la reclamación transcurridos tres años desde su registro.

## Diagrama de arquitectura del sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-ad"></a>

A continuación, se muestra el diagrama de arquitectura del sistema de administración de reclamaciones. Este diagrama muestra las diferentes integraciones de Servicio de AWS que utiliza el sistema de administración de reclamaciones.

![\[Flujo de trabajo combinado para cumplir con requisitos no transaccionales mediante integraciones con varios Servicios de AWS.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-1-AD.jpg)


Aparte de los patrones de acceso transaccional de clave-valor que trataremos más adelante en la sección de modelado de datos de DynamoDB, tenemos tres requisitos no transaccionales. El diagrama de arquitectura anterior puede desglosarse en los tres flujos de trabajo siguientes:

1. Enviar una notificación cuando se agregue un nuevo comentario a una reclamación

1. Ejecutar consultas analíticas sobre los datos semanales

1. Archivar datos de más de tres años

Echemos un vistazo más a fondo a cada una de ellas.

**Enviar una notificación cuando se agregue un nuevo comentario a una reclamación**

Podemos utilizar el siguiente flujo de trabajo para cumplir este requisito:

![\[Flujo de trabajo para invocar funciones de Lambda para enviar notificaciones basadas en los cambios registrados por DynamoDB Streams.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-2-Workflow1.jpg)


[DynamoDB Streams](Streams.md) es un mecanismo de captura de datos de cambios para registrar toda la actividad de escritura en sus tablas de DynamoDB. Puede configurar funciones de Lambda para desencadenar algunos o todos estos cambios. Se puede configurar un [filtro de eventos](https://docs.aws.amazon.com/lambda/latest/dg/invocation-eventfiltering.html) en los desencadenadores de Lambda para filtrar los eventos que no sean pertinentes para el caso de uso. En este caso, podemos utilizar un filtro para desencadenar Lambda solo cuando se agregue un nuevo comentario y enviar una notificación a los ID de correo electrónico pertinentes, que pueden obtenerse de [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) o de cualquier otro almacén de credenciales.

**Ejecutar consultas analíticas sobre los datos semanales**

DynamoDB es adecuado para cargas de trabajo centradas principalmente en el procesamiento transaccional en línea (OLTP). Para el otro 10 % a 20 % de patrones de acceso con requisitos analíticos, los datos pueden exportarse a S3 con la característica administrada [Exportar a Amazon S3](S3DataExport.HowItWorks.md) sin impacto en el tráfico en directo de la tabla de DynamoDB. Examinemos este flujo de trabajo:

![\[Flujo de trabajo para invocar periódicamente una función de Lambda para almacenar datos de DynamoDB en un bucket de Amazon S3.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-3-Workflow2.jpg)


[Amazon EventBridge](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-what-is) puede utilizarse para desencadenar AWS Lambda de forma programada: permite configurar una expresión cron para que la invocación de Lambda tenga lugar periódicamente. Lambda puede invocar la llamada a la API `ExportToS3` y almacenar los datos de DynamoDB en S3. A continuación, un motor SQL como [Amazon Athena](https://docs.aws.amazon.com/athena/latest/ug/what-is) puede acceder a estos datos de S3 para ejecutar consultas analíticas en los datos de DynamoDB sin que se vea afectada la carga de trabajo transaccional en directo de la tabla. Un ejemplo de consulta de Athena para hallar el número de reclamaciones por nivel de gravedad tendría el siguiente aspecto:

```
SELECT Item.severity.S as "Severity", COUNT(Item) as "Count"
FROM "complaint_management"."data"
WHERE NOT Item.severity.S = ''
GROUP BY Item.severity.S ;
```

Esto da como resultado la siguiente consulta de Athena:

![\[Los resultados de la consulta de Athena muestran el número de reclamaciones para los niveles de gravedad P3, P2 y P1.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-4-Athena.png)


**Archivar datos de más de tres años**

Puede aprovechar la característica [Tiempo de vida (TTL)](TTL.md) de DynamoDB para eliminar datos obsoletos de su tabla de DynamoDB sin costo adicional (excepto en el caso de las réplicas de tablas globales para la versión 2019.11.21 (actual), donde las eliminaciones TTL replicadas a otras regiones consumen capacidad de escritura). Estos datos aparecen y se pueden consumir desde DynamoDB Streams para archivarse en Amazon S3. El flujo de trabajo para este requisito es el siguiente:

![\[Flujo de trabajo para archivar datos antiguos en un bucket de Amazon S3 mediante la característica TTL y DynamoDB Streams.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-5-Workflow3.jpg)


## Diagrama de relaciones entre entidades del sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para el diseño del esquema del sistema de administración de reclamaciones. 

![\[Sistema de administración de reclamaciones ERD que muestra las entidades cliente, reclamación, comentario y agente.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-6-ERD.jpg)


## Patrones de acceso al sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-access-patterns"></a>

Estos son los patrones de acceso que tendremos en cuenta para el diseño del esquema de administración de reclamaciones.

1. createComplaint

1. updateComplaint

1. updateSeveritybyComplaintID

1. getComplaintByComplaintID

1. addCommentByComplaintID

1. getAllCommentsByComplaintID

1. getLatestCommentByComplaintID

1. getAComplaintbyCustomerIDAndComplaintID

1. getAllComplaintsByCustomerID

1. escalateComplaintByComplaintID

1. getAllEscalatedComplaints

1. getEscalatedComplaintsByAgentID (orden de más reciente a más antiguo)

1. getCommentsByAgentID (entre dos fechas)

## Evolución del diseño del esquema del sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-design-evolution"></a>

Al tratarse de un sistema de administración de reclamaciones, la mayoría de los patrones de acceso giran en torno a la reclamación como entidad principal. El valor de `ComplaintID`, al ser altamente cardinal, garantizará una distribución uniforme de los datos en las particiones subyacentes y es también el criterio de búsqueda más común para nuestros patrones de acceso identificados. Por lo tanto, `ComplaintID` es una buena candidata a clave de partición en este conjunto de datos.

**Paso 1: Abordar los patrones de acceso 1 (`createComplaint`), 2 (`updateComplaint`), 3 (`updateSeveritybyComplaintID`) y 4 (`getComplaintByComplaintID`) **

Podemos utilizar una clave de clasificación genérica valorada como “metadatos” (o “AA”) para almacenar información específica de la reclamación como `CustomerID`, `State`, `Severity` y `CreationDate`. Utilizamos operaciones singleton con `PK=ComplaintID` y `SK=“metadata”` para hacer lo siguiente:

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html) para crear una nueva reclamación

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html) para actualizar la gravedad u otros campos de los metadatos de la reclamación

1. [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) para obtener los metadatos de la reclamación

![\[Los valores de la clave principal, la clave de clasificación y los atributos, como el customer_id y la gravedad, de un elemento de reclamación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-7-Step1.png)


**Paso 2: Abordar el patrón de acceso 5 (`addCommentByComplaintID`)**

Este patrón de acceso requiere un modelo de relación de uno a varios entre una reclamación y los comentarios sobre ella. Aquí utilizaremos la técnica de [partición vertical](data-modeling-blocks.md#data-modeling-blocks-vertical-partitioning) para utilizar una clave de clasificación y crear una colección de elementos con distintos tipos de datos. Si observamos los patrones de acceso 6 (`getAllCommentsByComplaintID`) y 7 (`getLatestCommentByComplaintID`), sabremos que los comentarios deberán ordenarse por tiempo. También podemos tener varios comentarios que lleguen al mismo tiempo, por lo que podemos utilizar la técnica de [clave de clasificación compuesta](data-modeling-blocks.md#data-modeling-blocks-composite) para agregar la hora y `CommentID` en el atributo de clave de clasificación.

Otras opciones para tratar estas posibles colisiones de comentarios serían aumentar la granularidad para la marca de tiempo o agregar un número incremental como sufijo en lugar de utilizar `Comment_ID`. En este caso, antepondremos el prefijo “comm\$1” al valor de la clave de clasificación de los elementos correspondientes a comentarios para permitir operaciones basadas en intervalos.

También tenemos que asegurarnos de que `currentState` en los metadatos de la reclamación refleja el estado cuando se agrega un nuevo comentario. Agregar un comentario puede indicar que la reclamación se ha asignado a un agente o que se ha resuelto, etc. Para agrupar la adición de comentarios y la actualización del estado actual en los metadatos de la reclamación, de forma que todo sea posible, utilizaremos la API [TransactWriteItems](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactWriteItems.html). El estado de la tabla resultante tiene ahora este aspecto:

![\[Tabla para almacenar una reclamación con sus comentarios como una relación de uno a varios mediante una clave de clasificación compuesta.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-8-Step2.png)


Vamos a agregar algunos datos más en la tabla y también agregar `ComplaintID` como un campo separado de nuestro `PK` para preparar el modelo para el futuro en caso de que necesitemos índices adicionales en `ComplaintID`. Tenga en cuenta también que algunos comentarios pueden tener archivos adjuntos que almacenaremos en Amazon Simple Storage Service y solo mantendremos sus referencias o URL en DynamoDB. Se recomienda mantener la base de datos transaccional lo más reducida posible para optimizar los costos y el rendimiento. Los datos ahora tienen este aspecto:

![\[Tabla con los metadatos de las reclamaciones y los datos de todos los comentarios asociados a cada reclamación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-9-Step3.png)


**Paso 3: Abordar patrones de acceso 6 (`getAllCommentsByComplaintID`) y 7 (`getLatestCommentByComplaintID`)**

Para obtener todos los comentarios de una reclamación, podemos utilizar la operación [`query`](Query.md) con la condición `begins_with` en la clave de clasificación. En lugar de consumir capacidad de lectura adicional para leer la entrada de metadatos y, a continuación, tener la sobrecarga de filtrar los resultados relevantes, tener una condición de clave de clasificación como esta nos ayuda a leer solo lo que necesitamos. Por ejemplo, una operación de consulta con `PK=Complaint123` y `SK` begins\$1with `comm#` devolvería lo siguiente al mismo tiempo que omitiría la entrada de metadatos:

![\[Consulte el resultado de la operación mediante una condición de clave de clasificación que solo muestra comentarios de una reclamación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-10-Step4.png)


Puesto que necesitamos el último comentario de una reclamación en el patrón 7 (`getLatestCommentByComplaintID`), vamos a utilizar dos parámetros de consulta adicionales:

1. `ScanIndexForward` debe configurarse en False para que los resultados se ordenen en orden descendente

1. `Limit` debe configurarse en 1 para obtener el último comentario (solo uno)

De forma similar al patrón de acceso 6 (`getAllCommentsByComplaintID`), omitimos la entrada de metadatos mediante `begins_with` `comm#` como la condición de clave de clasificación. Ahora, puede realizar el patrón de acceso 7 en este diseño mediante la operación de consulta con `PK=Complaint123` y `SK=begins_with comm#`, `ScanIndexForward=False` y `Limit` 1. Como resultado se devolverá el siguiente elemento objetivo:

![\[El resultado de la operación de consulta mediante una condición de clave de clasificación para obtener un comentario de la última reclamación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-11-Step5.png)


Agreguemos más datos ficticios a la tabla.

![\[Tabla con datos ficticios para obtener los últimos comentarios sobre las reclamaciones recibidas.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-12-Step6.png)


**Paso 4: Abordar patrones de acceso 8 (`getAComplaintbyCustomerIDAndComplaintID`) y 9 (`getAllComplaintsByCustomerID`)**

El acceso a los patrones 8 (`getAComplaintbyCustomerIDAndComplaintID`) y 9 (`getAllComplaintsByCustomerID`) presenta un nuevo criterio de búsqueda: `CustomerID`. Recuperarlo de la tabla existente requiere un proceso [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html) costoso de lectura de todos los datos y, a continuación, filtrar los elementos relevantes para `CustomerID` en cuestión. Podemos hacer que esta búsqueda sea más eficaz mediante la creación de un [índice secundario global (GSI)](GSI.md) con `CustomerID` como clave de partición. Teniendo en cuenta la relación de uno a varios entre cliente y reclamaciones, así como el patrón de acceso 9 (`getAllComplaintsByCustomerID`), `ComplaintID` sería el candidato adecuado para la clave de clasificación.

Los datos del GSI tendrían este aspecto:

![\[GSI con un modelo de relación de uno a varios para obtener todas las reclamaciones de un CustomerID específico.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-13-Step4-GSI.png)


 Un ejemplo de consulta en este GSI para el patrón de acceso 8 (`getAComplaintbyCustomerIDAndComplaintID`) sería: `customer_id=custXYZ`, `sort key=Complaint1321`. El resultado sería:

![\[Consulte el resultado de una operación en un GSI para obtener datos sobre una reclamación específica de un cliente determinado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-14-Step4-8.png)


Para obtener todas las reclamaciones de un cliente para el patrón de acceso 9 (`getAllComplaintsByCustomerID`), la consulta del GSI sería: `customer_id=custXYZ` como condición de clave de partición. El resultado sería:

![\[Consulte el resultado de una operación mediante una condición de clave de partición para obtener todas las reclamaciones de un cliente determinado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-15-Step4-9.png)


**Paso 5: Abordar el patrón de acceso 10 (`escalateComplaintByComplaintID`)**

Este acceso introduce el aspecto de escalado. Para escalar una reclamación, podemos utilizar `UpdateItem` para agregar atributos como `escalated_to` y `escalation_time` al elemento de metadatos de reclamación existente. DynamoDB proporciona un diseño de esquema flexible, lo que significa que un conjunto de atributos no clave puede ser uniforme o discreto en diferentes elementos. Consulte a continuación un ejemplo:

`UpdateItem with PK=Complaint1444, SK=metadata`

![\[Resultado de la actualización de los metadatos de las reclamaciones mediante la operación de la API UpdateItem.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-16-Step5.png)


**Paso 6: Abordar patrones de acceso 11 (`getAllEscalatedComplaints`) y 12 (`getEscalatedComplaintsByAgentID`)**

De todo el conjunto de datos, solo se espera que se escalen unas pocas reclamaciones. Por lo tanto, la creación de un índice sobre los atributos relacionados con el escalado conduciría a búsquedas eficientes, así como a un almacenamiento de GSI rentable. Podemos hacerlo aprovechando la técnica del [índice disperso](data-modeling-blocks.md#data-modeling-blocks-sparse-index). El GSI con clave de partición como `escalated_to` y clave de clasificación como `escalation_time` tendría el siguiente aspecto:

![\[Diseño de GSI con los atributos relacionados con la escalada, escalated_to y escalation_time.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-17-Step6.png)


Para obtener todas las reclamaciones escaladas para el patrón de acceso 11 (`getAllEscalatedComplaints`), simplemente escaneamos este GSI. Tenga en cuenta que esta escaneo será eficaz y rentable debido al tamaño del GSI. Para obtener reclamaciones escaladas para un agente específico (patrón de acceso 12 [`getEscalatedComplaintsByAgentID`]), la clave de partición sería `escalated_to=agentID` y establecemos `ScanIndexForward` a`False`  para ordenar de más reciente a más antiguo.

**Paso 7: Abordar el patrón de acceso 13 (`getCommentsByAgentID`)**

Para el último patrón de acceso, necesitamos realizar una búsqueda por una nueva dimensión: `AgentID`. También necesitamos una ordenación basada en el tiempo para leer los comentarios entre dos fechas, así que creamos un GSI con `agent_id` como la clave de partición y `comm_date` como la clave de clasificación. Los datos de este GSI tendrán el siguiente aspecto:

![\[Diseño de GSI para buscar comentarios de un agente determinado ordenados por fecha de comentario.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-18.png)


Un ejemplo de consulta en este GSI sería `partition key agentID=AgentA` y `sort key=comm_date between (2023-04-30T12:30:00, 2023-05-01T09:00:00)`, cuyo resultado es:

![\[Resultado de una consulta con una clave de partición y una clave de clasificación en un GSI.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-19.png)


En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | Otras condiciones/filtros | 
| --- | --- | --- | --- | --- | --- | 
| createComplaint | Tabla de base | PutItem | PK=complaint\$1id | SK=metadata |  | 
| updateComplaint | Tabla de base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| updateSeveritybyComplaintID | Tabla de base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| getComplaintByComplaintID | Tabla de base | GetItem | PK=complaint\$1id | SK=metadata |  | 
| addCommentByComplaintID | Tabla de base | TransactWriteItems | PK=complaint\$1id | SK=metadata, SK=comm\$1comm\$1date\$1comm\$1id |  | 
| getAllCommentsByComplaintID | Tabla de base | Consultar | PK=complaint\$1id | SK begins\$1with “comm\$1” |  | 
| getLatestCommentByComplaintID | Tabla de base | Consultar | PK=complaint\$1id | SK begins\$1with “comm\$1” | scan\$1index\$1forward=False, Limit 1 | 
| getAComplaintbyCustomerIDAndComplaintID | Customer\$1complaint\$1GSI | Consultar | customer\$1id=customer\$1id | complaint\$1id = complaint\$1id |  | 
| getAllComplaintsByCustomerID | Customer\$1complaint\$1GSI | Consultar | customer\$1id=customer\$1id | N/A |  | 
| escalateComplaintByComplaintID | Tabla de base | UpdateItem | PK=complaint\$1id | SK=metadata |  | 
| getAllEscalatedComplaints | Escalations\$1GSI | Examen | N/A | N/A |  | 
| getEscalatedComplaintsByAgentID (orden de más reciente a más antiguo) | Escalations\$1GSI | Consultar | escalated\$1to=agent\$1id | N/A | scan\$1index\$1forward=False | 
| getCommentsByAgentID (entre dos fechas) | Agents\$1Comments\$1GSI | Consultar | agent\$1id=agent\$1id | SK entre (fecha1, fecha2) |  | 

## Esquema final del sistema de administración de reclamaciones
<a name="data-modeling-schema-complaint-management-final-schema"></a>

Estos son los diseños finales del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte los [ejemplos de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/ComplainManagement/ComplaintManagementSchema.json) en GitHub.

**Tabla base**

![\[Diseño de tabla base con metadatos de reclamaciones.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-20-Complaint_management_system.png)


**Customer\$1Complaint\$1GSI**

![\[Diseño GSI que muestra las reclamaciones de un cliente determinado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-21-Customer_Complaint_GSI.png)


**Escalations\$1GSI**

![\[Diseño de GSI que muestra los atributos relacionados con la escalada.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-22-Escalations_GSI.png)


**Agents\$1Comments\$1GSI**

![\[Diseño de GSI que muestra los comentarios realizados por un agente determinado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ComplaintManagement-23-Comments_GSI.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-complaint-management-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Diseño del esquema de pagos periódicos en DynamoDB
<a name="data-modeling-schema-recurring-payments"></a>

## Caso de uso empresarial de pagos periódicos
<a name="data-modeling-schema-recurring-payments-use-case"></a>

En este caso de uso se habla de utilizar DynamoDB para implementar un sistema de pagos periódicos. El modelo de datos tiene las siguientes entidades: *cuentas*, *suscripciones* y *recibos*. Los detalles específicos para nuestro caso de uso son los siguientes:
+ Cada *cuenta* puede tener varias *suscripciones*
+ La *suscripción* tiene una `NextPaymentDate` en la que se debe procesar el siguiente pago y una `NextReminderDate` en la que se envía un recordatorio por correo electrónico al cliente
+ Existe un elemento para la *suscripción* que se almacena y actualiza cuando se procesa el pago (el tamaño medio del elemento es de alrededor de 1 KB y el rendimiento depende del número de *cuentas* y *suscripciones*).
+ El procesador de *pagos* también creará un *recibo* como parte del proceso que se almacena en la tabla y se establece a expirar después de un periodo de tiempo mediante un atributo [TTL](TTL.md)

## Diagrama de relación entre entidades de pagos periódicos
<a name="data-modeling-schema-recurring-payments-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para el diseño del esquema del sistema de pagos periódicos.

![\[Sistema de pagos recurrentes ERD que muestra las entidades: cuenta, suscripción y recibo.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-1-ERD.png)


## Patrones de acceso al sistema de pagos periódicos
<a name="data-modeling-schema-recurring-payments-access-patterns"></a>

Estos son los patrones de acceso que tendremos en cuenta para el diseño del esquema del sistema de pagos periódicos.

1. `createSubscription`

1. `createReceipt`

1. `updateSubscription`

1. `getDueRemindersByDate`

1. `getDuePaymentsByDate`

1. `getSubscriptionsByAccount`

1. `getReceiptsByAccount`

## Diseño del esquema de pagos periódicos
<a name="data-modeling-schema-recurring-payments-design-evolution"></a>

Los nombres genéricos `PK` y `SK` se utilizan para atributos de clave que permiten almacenar distintos tipos de entidades en la misma tabla, como las entidades de cuenta, suscripción y recibo. En primer lugar, el usuario crea una suscripción, por la que se compromete a pagar una cantidad el mismo día cada mes a cambio de un producto. Puede elegir qué día del mes se procesa el pago. También se enviará un recordatorio antes de que se procese el pago. La aplicación funciona mediante dos trabajos por lotes que se ejecutan cada día: un trabajo por lotes envía los recordatorios que vencen ese día y el otro procesa los pagos que vencen ese día.

**Paso 1: Abordar el patrón de acceso 1 (`createSubscription`)**

El patrón de acceso 1 (`createSubscription`) se utiliza para crear inicialmente la suscripción y se establecen los detalles, como `SKU`, `NextPaymentDate`, `NextReminderDate` y `PaymentDetails`. En este paso se muestra el estado de la tabla para una sola cuenta con una suscripción. Puede haber varias suscripciones en la colección de elementos, por lo que se trata de una relación de uno a varios.

![\[Diseño de tabla que muestra los detalles de la suscripción de una cuenta.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-2-Step1.png)


**Paso 2: Abordar patrones de acceso 2 (`createReceipt`) y 3 (`updateSubscription`)**

Se utiliza el patrón de acceso 2 (`createReceipt`) para crear el elemento de recibo. Una vez procesado el pago cada mes, el procesador de pagos volverá a escribir un recibo en la tabla base. Puede haber varios recibos en la colección de elementos, por lo que se trata de una relación de uno a varios. El procesador de pagos también actualizará el elemento de suscripción (patrón de acceso 3 [`updateSubscription`]) para actualizar para la `NextReminderDate` o la `NextPaymentDate` del mes siguiente.

![\[Los detalles del recibo y el artículo de suscripción se actualizan para mostrar la siguiente fecha de recordatorio de suscripción.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-3-Step2.png)


**Paso 3: Abordar el patrón de acceso 4 (`getDueRemindersByDate`)**

La aplicación procesa los recordatorios de pago por lotes correspondientes al día en curso. Por lo tanto, la aplicación necesita acceder a las suscripciones en una dimensión diferente: fecha en lugar de cuenta. Este es un buen caso de uso para un [índice secundario global (GSI)](GSI.md). En este paso agregamos el índice `GSI-1`, que utiliza la `NextReminderDate` como clave de partición de GSI. No necesitamos replicar todos los elementos. Este GSI es un [índice disperso](data-modeling-blocks.md#data-modeling-blocks-sparse-index) y los elementos de entrada no están replicados. Tampoco necesitamos proyectar todos los atributos, solo necesitamos incluir un subconjunto de ellos. En la imagen siguiente se muestra el esquema de `GSI-1` y se proporciona la información necesaria para que la aplicación envíe el correo electrónico de recordatorio.

![\[Esquema de GSI-1 con detalles, como la dirección de correo electrónico, la aplicación debe enviar un correo electrónico de recordatorio.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-4-Step3.png)


**Paso 4: Abordar el patrón de acceso 5 (`getDuePaymentsByDate`)**

La aplicación procesa los pagos en lotes para el día en curso del mismo modo que lo hace con los recordatorios. Agregamos `GSI-2` en este paso y utiliza la `NextPaymentDate` como la clave de partición de GSI. No necesitamos replicar todos los elementos. Este GSI es un índice disperso, ya que los elementos de entrada no están replicados. En la imagen siguiente se muestra el esquema de `GSI-2`.

![\[Esquema de GSI-2 con detalles para procesar los pagos. NextPaymentDate es la clave de partición para GSI-2.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-5-Step4.png)


**Paso 5: Abordar patrones de acceso 6 (`getSubscriptionsByAccount`) y 7 (`getReceiptsByAccount`)**

La aplicación puede recuperar todas las suscripciones de una cuenta mediante una [consulta](Query.md) en la tabla base que se dirige al identificador de la cuenta (el `PK`) y utiliza el operador de intervalo para obtener todos los elementos en los que el `SK` comienza por “SUB\$1”. La aplicación también puede utilizar la misma estructura de consulta para recuperar todos los recibos empleando un operador de intervalo para obtener todos los elementos en los que el `SK` comience por “REC\$1”. Esto nos permite satisfacer los patrones de acceso 6 (`getSubscriptionsByAccount`) y 7 (`getReceiptsByAccount`). La aplicación utiliza estos patrones de acceso para que el usuario pueda ver sus suscripciones actuales y sus recibos anteriores de los últimos seis meses. No hay ningún cambio en el esquema de la tabla en este paso y podemos ver a continuación cómo nos dirigimos solo a los elementos de suscripción en el patrón de acceso 6 (`getSubscriptionsByAccount`).

![\[Resultado de la operación de consulta en la tabla base. Muestra la suscripción de una cuenta específica.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-6-Step5.png)


En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | 
| --- | --- | --- | --- | --- | 
| createSubscription | Tabla de base | PutItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| createReceipt | Tabla de base | PutItem | ACC\$1account\$1id | REC\$1<RecieptDate>\$1SKU<SKUID> | 
| updateSubscription | Tabla de base | UpdateItem | ACC\$1account\$1id | SUB\$1<SUBID>\$1SKU<SKUID> | 
| getDueRemindersByDate | GSI-1 | Consultar | <NextReminderDate> |  | 
| getDuePaymentsByDate | GSI-2 | Consultar | <NextPaymentDate> |  | 
| getSubscriptionsByAccount | Tabla de base | Consultar | ACC\$1account\$1id | SK begins\$1with “SUB\$1” | 
| getReceiptsByAccount | Tabla de base | Consultar | ACC\$1account\$1id | SK begins\$1with “REC\$1” | 

## Esquema final de pagos periódicos
<a name="data-modeling-schema-recurring-payments-final-schema"></a>

Estos son los diseños finales del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte los [ejemplos de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/blob/master/schema_design/SchemaExamples/ReocurringPayments/ReocurringPaymentsSchema.json) en GitHub.

**Tabla base**

![\[Diseño de tabla base que muestra información de la cuenta y sus detalles de suscripción y recibo.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-7-Base.png)


**GSI-1**

![\[Esquema de GSI-1 con detalles de la suscripción, como la dirección de correo electrónico y NextPaymentDate.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-8-GSI1.png)


**GSI-2**

![\[Esquema de GSI-2 con detalles de pago, como PaymentAmount y PaymentDay.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/ReoccurringPayments-9-GSI2.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-recurring-payments-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Monitoreo de las actualizaciones de estado de los dispositivos en DynamoDB
<a name="data-modeling-device-status"></a>

En este caso de uso se habla de utilizar DynamoDB para monitorear las actualizaciones del estado del dispositivo (o los cambios en el estado del dispositivo) en DynamoDB.

## Caso de uso
<a name="data-modeling-schema-device-status-use-case"></a>

En los casos de uso de IoT (una fábrica inteligente, por ejemplo), los operadores deben monitorear muchos dispositivos y estos envían periódicamente su estado o sus registros a un sistema de monitoreo. Cuando hay un problema con un dispositivo, el estado del mismo cambia de *normal* a *advertencia*. Existen diferentes niveles o estados de registro en función de la gravedad y el tipo de comportamiento anómalo del dispositivo. A continuación, el sistema asigna a un operario para que compruebe el dispositivo y este puede escalar el problema a su supervisor si es necesario.

Algunos patrones de acceso típicos de este sistema son:
+ Crear una entrada de registro para un dispositivo
+ Obtener todos los registros para un estado de dispositivo específico mostrando primero los registros más recientes
+ Obtener todos los registros de un operador dado entre dos fechas
+ Obtener todos los registros escalados de un supervisor determinado
+ Obtener todos los registros escalados con un estado de dispositivo específico para un supervisor determinado
+ Obtener todos los registros escalados con un estado de dispositivo específico para un supervisor determinado en una fecha concreta

## Diagrama de relaciones entre entidades
<a name="data-modeling-schema-device-status-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para monitorear las actualizaciones del estado de los dispositivos.

![\[Actualizaciones del ERD de estado de los dispositivos. Muestra las entidades: Dispositivo y Operador.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-1-ERD.jpg)


## Patrones de acceso
<a name="data-modeling-schema-device-status-access-patterns"></a>

Estos son los patrones de acceso que tendremos en cuenta para monitorear las actualizaciones de estado de los dispositivos.

1. `createLogEntryForSpecificDevice`

1. `getLogsForSpecificDevice`

1. `getWarningLogsForSpecificDevice`

1. `getLogsForOperatorBetweenTwoDates`

1. `getEscalatedLogsForSupervisor`

1. `getEscalatedLogsWithSpecificStatusForSupervisor`

1. `getEscalatedLogsWithSpecificStatusForSupervisorForDate`

## Evolución del diseño de esquema
<a name="data-modeling-schema-device-status-design-evolution"></a>

**Paso 1: Abordar patrones de acceso 1 (`createLogEntryForSpecificDevice`) y 2 (`getLogsForSpecificDevice`)**

La unidad de escala para un sistema de seguimiento de dispositivos serían los dispositivos individuales. En este sistema, un `deviceID` identifica de forma única a un dispositivo. Esto convierte a `deviceID` en un buen candidato para la clave de partición. Cada dispositivo envía información al sistema de seguimiento periódicamente ( por ejemplo, cada cinco minutos más o menos). Esta ordenación convierte a la fecha en un criterio lógico de clasificación y, por tanto, en la clave de clasificación. Los datos de muestra en este caso tendrían este aspecto:

![\[Tabla para almacenar el estado de varios dispositivos. DeviceID es la clave principal y la fecha de actualización de estado es la clave de clasificación.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-2-Step1.png)


Para recuperar las entradas de registro de un dispositivo concreto, podemos realizar una operación de [consulta](Query.md) con clave de partición `DeviceID="d#12345"`.

**Paso 2: Abordar el patrón de acceso 3 (`getWarningLogsForSpecificDevice`)**

Dado que `State` es un atributo no clave, abordar el patrón de acceso 3 con el esquema actual requeriría una [expresión de filtro](Query.FilterExpression.md). En DynamoDB, las expresiones de filtro se aplican después de leer los datos mediante expresiones de condición clave. Por ejemplo, si quisiéramos obtener los registros de advertencias de `d#12345`, la operación de consulta con clave de partición `DeviceID="d#12345"` leerá cuatro elementos de la tabla anterior y, a continuación, filtrará el único elemento sin el estado de *advertencia*. Este enfoque no es eficiente a escala. Una expresión de filtro puede ser una buena forma de excluir elementos consultados si la proporción de elementos excluidos es baja o la consulta se realiza con poca frecuencia. No obstante, para los casos en los que se recuperan muchos elementos de una tabla y la mayoría de los elementos se filtran, podemos seguir evolucionando el diseño de nuestra tabla para que funcione de forma más eficiente.

Cambiemos la forma de gestionar este patrón de acceso mediante [claves de clasificación compuestas](data-modeling-blocks.md#data-modeling-blocks-composite). Puede importar datos de muestra de [DeviceStateLog\$13.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_3.json), donde la clave de clasificación se cambia a `State#Date`. Esta clave de clasificación es la composición de los atributos `State`, `#` y `Date`. En este ejemplo, `#` se utiliza como delimitador. Los datos tienen ahora este aspecto: 

![\[Los datos de actualización de estado del dispositivo, d#12345, se obtuvieron con la clave de clasificación compuesta State#Date.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-3-Step2.png)


Para obtener solo los registros de advertencia de un dispositivo, la consulta se vuelve más específica con este esquema. La condición clave para la consulta utiliza la clave de partición `DeviceID="d#12345"` y la clave de clasificación `State#Date begins_with “WARNING”`. Esta consulta solo leerá los tres elementos relevantes con el estado de *advertencia*.

**Paso 3: Abordar el patrón de acceso 4 (`getLogsForOperatorBetweenTwoDates`)**

Puede importar [DeviceStateLog\$14.jsonD](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_4.json), donde se agregó el atributo `Operator` a la tabla `DeviceStateLog` con datos de ejemplo.

![\[Diseño de tabla DeviceStateLog con el atributo Operador para obtener los registros de un operador entre fechas específicas.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-4-Step3.png)


Dado que `Operator` no es actualmente una clave de partición, no hay forma de realizar una búsqueda directa de clave-valor en esta tabla basada en `OperatorID`. Tendremos que crear una nueva [colección de elementos](WorkingWithItemCollections.md) con un índice secundario global en `OperatorID`. El patrón de acceso requiere una búsqueda basada en fechas, por lo que Fecha es el atributo de clave de clasificación para el [índice secundario global (GSI)](GSI.md). Este es el aspecto actual del GSI:

![\[Diseño de GSI con OperatorID y Fecha como clave de partición y clave de clasificación para obtener los registros de un operador específico.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-5-Step3.png)


Para el patrón de acceso 4 (`getLogsForOperatorBetweenTwoDates`), puede consultar este GSI con clave de partición `OperatorID=Liz` y clave de clasificación `Date` entre `2020-04-11T05:58:00` y `2020-04-24T14:50:00`.

![\[Consultas en GSI con OperatorID y Fecha para obtener los registros de un operador entre dos fechas.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-6-GSI1_1.png)


**Paso 4: Abordar patrones de acceso 5 (`getEscalatedLogsForSupervisor`), 6 (`getEscalatedLogsWithSpecificStatusForSupervisor`) y 7 (`getEscalatedLogsWithSpecificStatusForSupervisorForDate`)**

Utilizaremos un [índice disperso](data-modeling-blocks.md#data-modeling-blocks-sparse-index) para abordar estos patrones de acceso.

Los índices secundarios globales son dispersos de forma predeterminada, por lo que solo aparecerán en el índice los elementos de la tabla base que contengan atributos de clave principal del índice. Esta es otra forma de excluir elementos que no son relevantes para el patrón de acceso que se está modelando.

Puede importar [DeviceStateLog\$16.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/device-state-log/json/DeviceStateLog_6.json), donde se agregó el atributo `EscalatedTo` a la tabla `DeviceStateLog` con datos de ejemplo. Como ya se ha mencionado, no todos los registros se escalan a un supervisor.

![\[Diseño de GSI con el atributo EscalatedTo para obtener todos los registros escalados de un supervisor.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-7-Step4.png)


Ahora puede crear un nuevo GSI en el que `EscalatedTo` es la clave de partición y `State#Date` es la clave de clasificación. Observe que solo aparecen en el índice los elementos que tienen los atributos `EscalatedTo` y `State#Date`.

![\[Diseño de GSI para obtener todos los elementos con los atributos EscalatedTo y State#Date.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-8-Step4.png)


El resto de los patrones de acceso se resumen como sigue:

    Para el patrón de acceso 5 (getEscalatedLogsForSupervisor), puede realizar una consulta en el GSI de escalados con la clave de partición EscalatedTo=“Sara”   Para el patrón de acceso 6 (getEscalatedLogsWithSpecificStatusForSupervisor), puede realizar una consulta en el GSI de escalados con clave de partición EscalatedTo=“Sara” y clave de clasificación State\$1Date begins\$1with “WARNING”.    Para el patrón de acceso 7 (getEscalatedLogsWithSpecificStatusForSupervisorForDate), puede realizar una consulta en el GSI de escalados con clave de partición EscalatedTo=“Sara” y clave de clasificación State\$1Date begins\$1with “WARNING4\$12020-04-27”.    

En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | Otras condiciones/filtros | 
| --- | --- | --- | --- | --- | --- | 
| createLogEntryForSpecificDevice | Tabla de base | PutItem | DeviceID=deviceId | State\$1Date=state\$1date |  | 
| getLogsForSpecificDevice | Tabla de base | Consultar | DeviceID=deviceId | State\$1Date begins\$1with “state1\$1” | ScanIndexForward = False | 
| getWarningLogsForSpecificDevice | Tabla de base | Consultar | DeviceID=deviceId | State\$1Date begins\$1with “WARNING” |  | 
| getLogsForOperatorBetweenTwoDates | GSI-1 | Consultar | Operator=operatorName | Date between date1 and date2 |  | 
| getEscalatedLogsForSupervisor | GSI-2 | Consultar | EscalatedTo=supervisorName |  |  | 
| getEscalatedLogsWithSpecificStatusForSupervisor | GSI-2 | Consultar | EscalatedTo=supervisorName | State\$1Date begins\$1with “state1\$1” |  | 
| getEscalatedLogsWithSpecificStatusForSupervisorForDate | GSI-2 | Consultar | EscalatedTo=supervisorName | State\$1Date begins\$1with “state1\$1date1” |  | 

## Esquema final
<a name="data-modeling-schema-device-status-final-schema"></a>

Estos son los diseños finales del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte los [ejemplos de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/schema_design/SchemaExamples) en GitHub.

**Tabla base**

![\[Diseño de tabla base con metadatos del estado del dispositivo, como el ID del dispositivo, el estado y la fecha.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-9-Table.png)


**GSI-1**

![\[Diseño de GSI-1. Muestra la clave principal y los atributos: DeviceID, State#Date y Estado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-10-GSI1.png)


**GSI-2**

![\[Diseño de GSI-2. Muestra la clave principal y los atributos: DeviceID, Operador, Fecha y Estado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/DeviceStatus-11-GSI2.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-device-status-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Uso de DynamoDB como almacén de datos para una tienda en línea
<a name="data-modeling-online-shop"></a>

En este caso de uso se habla de utilizar DynamoDB como almacén de datos para una tienda en línea (o tienda electrónica).

## Caso de uso
<a name="data-modeling-schema-online-shop"></a>

Una tienda en línea permite a los usuarios navegar por diferentes productos y, finalmente, comprarlos. Basándose en la factura generada, el cliente puede pagar utilizando un código de descuento o una tarjeta regalo y, a continuación, abonar el importe restante con una tarjeta de crédito. Los productos adquiridos se retirarán de uno de varios almacenes y se enviarán a la dirección facilitada. Los patrones de acceso típicos de una tienda en línea incluyen:
+ Obtener el cliente para un customerId dado
+ Obtener el producto para un productId dado
+ Obtener almacén para un warehouseId dado
+ Obtener un inventario de productos para todos los almacenes por un productId
+ Obtener pedido para un orderId dado
+ Obtener todos los productos para un orderId dado
+ Obtener la factura de un orderId dado
+ Obtener todos los envíos para un orderId dado
+ Obtener todos los pedidos de un productId determinado para un intervalo de fechas dado
+ Obtener la factura para un invoiceId dado
+ Obtener todos los pagos para un invoiceId dado
+ Obtener los detalles de envío para un shipmentId dado
+ Obtener todos los envíos para un warehouseId dado
+ Obtener el inventario de todos los productos para un warehouseId dado
+ Obtener todas las facturas de un customerId determinado para un intervalo de fechas dado
+ Obtener todos los productos pedidos por un customerId determinado para un intervalo de fechas dado

## Diagrama de relaciones entre entidades
<a name="data-modeling-schema-online-shop-erd"></a>

Este es el diagrama de relaciones entre entidades (ERD) que utilizaremos para modelar DynamoDB como almacén de datos para una tienda en línea.

![\[ERD para un modelo de datos de almacenamiento en línea con entidades como el producto, el pedido, el pago y el cliente.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-1-ERD.png)


## Patrones de acceso
<a name="data-modeling-schema-online-shop-access-patterns"></a>

Estos son los patrones de acceso que tendremos en cuenta al utilizar DynamoDB como almacén de datos para una tienda en línea.

1. `getCustomerByCustomerId`

1. `getProductByProductId`

1. `getWarehouseByWarehouseId`

1. `getProductInventoryByProductId`

1. `getOrderDetailsByOrderId`

1. `getProductByOrderId`

1. `getInvoiceByOrderId`

1. `getShipmentByOrderId`

1. `getOrderByProductIdForDateRange`

1. `getInvoiceByInvoiceId`

1. `getPaymentByInvoiceId`

1. `getShipmentDetailsByShipmentId`

1. `getShipmentByWarehouseId`

1. `getProductInventoryByWarehouseId`

1. `getInvoiceByCustomerIdForDateRange`

1. `getProductsByCustomerIdForDateRange`

## Evolución del diseño de esquema
<a name="data-modeling-schema-online-shop-design-evolution"></a>

Mediante [NoSQL Workbench para DynamoDB](workbench.md), importe [AnOnlineShop\$11.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_1.json) para crear un nuevo modelo de datos llamado `AnOnlineShop` y una nueva tabla llamada `OnlineShop`. Tenga en cuenta que utilizamos los nombres genéricos `PK` y `SK` para la clave de partición y la clave de clasificación. Se trata de una práctica utilizada para almacenar distintos tipos de entidades en la misma tabla.

**Paso 1: Abordar el patrón de acceso 1 (`getCustomerByCustomerId`)**

Importe [AnOnlineShop\$12.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_2.json) para gestionar el patrón de acceso 1 (`getCustomerByCustomerId`). Algunas entidades no tienen relaciones con otras entidades, por lo que utilizaremos el mismo valor de `PK` y `SK` para ellas. En los datos del ejemplo, observe que las claves utilizan un prefijo `c#` para distinguir `customerId` de otras entidades que se agregarán posteriormente. Esta práctica se repite también para otras entidades. 

Para abordar este patrón de acceso, se puede utilizar una operación [https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html) con `PK=customerId` y `SK=customerId`.

**Paso 2: Abordar el patrón de acceso 2 (`getProductByProductId`)**

Importe [AnOnlineShop\$13.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_3.json) para abordar el patrón de acceso 2 (`getProductByProductId`) para la entidad `product`. Las entidades de producto tienen el prefijo `p#` y se ha utilizado el mismo atributo de clave de clasificación para almacenar `customerID` y `productID`. La denominación genérica y la [partición vertical](data-modeling-blocks.md#data-modeling-blocks-vertical-partitioning) nos permiten crear tales colecciones de elementos para un diseño eficaz de tabla única. 

Para abordar este patrón de acceso, se puede utilizar una operación `GetItem` con `PK=productId` y `SK=productId`.

**Paso 3: Abordar el patrón de acceso 3 (`getWarehouseByWarehouseId`)**

Importe [AnOnlineShop\$14.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_4.json) para abordar el patrón de acceso 3 (`getWarehouseByWarehouseId`) para la entidad `warehouse`. Actualmente tenemos las entidades `customer`, `product` y `warehouse` agregadas a la misma tabla. Se distinguen mediante prefijos y el atributo `EntityType`. Un atributo de tipo (o prefijo de nomenclatura) mejora la legibilidad del modelo. La legibilidad se vería afectada si simplemente almacenáramos ID alfanuméricos para diferentes entidades en el mismo atributo. Sería difícil distinguir una entidad de otra en ausencia de estos identificadores. 

Para abordar este patrón de acceso, se puede utilizar una operación `GetItem` con `PK=warehouseId` y `SK=warehouseId`.

**Tabla base:**

![\[Diseño de tabla de DynamoDB con prefijos y EntityType para obtener los datos del almacén por su ID.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-2-Step3.png)


**Paso 4: Abordar el patrón de acceso 4 (`getProductInventoryByProductId`)**

Importe [AnOnlineShop\$15.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_5.json) para abordar el patrón de acceso 4 (`getProductInventoryByProductId`). La entidad `warehouseItem` se utiliza para realizar un seguimiento del número de productos de cada almacén. Este elemento se actualizará normalmente cuando se agregue o elimine un producto de un almacén. Como se ve en el ERD, existe una relación de varios a varios entre `product` y `warehouse`. Aquí, la relación de uno a varios de `product` a `warehouse` se modela como `warehouseItem`. Más adelante, también se modelará la relación de uno a varios de `warehouse` a `product`. 

El patrón de acceso 4 puede abordarse con una consulta sobre `PK=ProductId` y `SK begins_with “w#“`. 

Para obtener más información sobre `begins_with()` y otras expresiones que pueden aplicarse a las claves de clasificación, consulte [Expresiones de condición de clave](Query.KeyConditionExpressions.md).

**Tabla base:**

![\[Diseño de tabla para consultar ProductID y WarehouseID para rastrear el inventario de productos en un almacén determinado.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-3-Step4.png)


**Paso 5: Abordar patrones de acceso 5 (`getOrderDetailsByOrderId`) y 6 (`getProductByOrderId`)**

Agregue más elementos `customer`, `product` y `warehouse` a la tabla mediante la importación de [AnOnlineShop\$16.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_6.json). A continuación, importe [AnOnlineShop\$17.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_7.json) para crear una colección de elementos a fin de que `order` pueda abordar los patrones de acceso 5 (`getOrderDetailsByOrderId`) y 6 (`getProductByOrderId`). Puede ver la relación de uno a varios entre `order` y `product` modelada como entidades orderItem. 

Para abordar el patrón de acceso 5 (`getOrderDetailsByOrderId`), consulte la tabla con `PK=orderId`. Esto le proporcionará toda la información sobre el pedido, incluidos `customerId` y los productos solicitados.

**Tabla base:**

![\[Diseño de tabla para realizar consultas mediante OrderID para obtener información sobre todos los productos pedidos.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-4-Step5.png)


Para abordar el patrón de acceso 6 (`getProductByOrderId`), necesitamos leer los productos en un `order` solamente. Consulte la tabla con `PK=orderId` y `SK begins_with “p#”` para conseguirlo.

**Tabla base:**

![\[Diseño de tabla para realizar consultas mediante OrderID y ProductID para obtener los productos de un pedido.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-5-Step5.png)


**Paso 6: Abordar el patrón de acceso 7 (`getInvoiceByOrderId`)**

Importe [AnOnlineShop\$18.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_8.json) para agregar una entidad `invoice` a la colección de elementos de *pedido* para gestionar el patrón de acceso 7 (`getInvoiceByOrderId`). Para abordar este patrón de acceso, puede utilizar una operación de consulta con `PK=orderId` y `SK begins_with “i#”`.

**Tabla base:**

![\[Diseño de tabla con la entidad de la factura en la recopilación de artículos del pedido para obtener una factura por OrderID.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-6-Step6.png)


**Paso 7: Abordar el patrón de acceso 8 (`getShipmentByOrderId`)**

Importe [AnOnlineShop\$19.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_9.json) para agregar entidades `shipment` a la colección de elementos de *pedido* para abordar el patrón de acceso 8 (`getShipmentByOrderId`). Estamos ampliando el mismo modelo particionado verticalmente mediante la adición de más tipos de entidades en un diseño de tabla única. Observe cómo la colección de elementos de *pedido* contiene las distintas relaciones que una entidad `order` tiene con las entidades `shipment`, `orderItem` y `invoice`. 

Para obtener envíos por `orderId`, puede realizar una operación de consulta con `PK=orderId` y `SK begins_with “sh#”`.

**Tabla base:**

![\[Diseño de tabla con la entidad de envío agregada a la recopilación de artículos del pedido para obtener los envíos por ID de pedido.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-7-Step7.png)


**Paso 8: Abordar el patrón de acceso 9 (`getOrderByProductIdForDateRange`)**

Hemos creado una colección de elementos de *pedido* en el paso anterior. Este patrón de acceso tiene nuevas dimensiones de búsqueda (`ProductID` y `Date`) que le obligan a escanear toda la tabla y filtrar los registros relevantes para obtener los elementos buscados. Para abordar este patrón de acceso, necesitaremos crear un [índice secundario global (GSI)](GSI.md). Importe [AnOnlineShop\$110.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_10.json) para crear una nueva colección de elementos mediante el GSI que permite recuperar datos `orderItem` de varias colecciones de elementos de *pedido*. Los datos tienen ahora `GSI1-PK` y `GSI1-SK`, que serán la clave de partición y la clave de clasificación de `GSI1`, respectivamente. 

DynamoDB rellena automáticamente los elementos que contienen los atributos clave de un GSI desde la tabla al GSI. No es necesario realizar manualmente ninguna inserción adicional en el GSI. 

Para abordar el patrón de acceso 9, realice una consulta de `GSI1` con `GSI1-PK=productId` y `GSI1SK between (date1, date2)`.

**Tabla base:**

![\[Diseño de tabla con un GSI para obtener datos de pedidos de varias recopilaciones de artículos de pedidos.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-8-Step8-Base.png)


**GSI1:**

![\[Diseño de GSI con ProductID y Fecha como claves de partición y clasificación para obtener pedidos por ID de producto y fecha.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-9-Step8-GSI.png)


**Paso 9: Abordar patrones de acceso 10 (`getInvoiceByInvoiceId`) y 11 (`getPaymentByInvoiceId`)**

Importe [AnOnlineShop\$111.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_11.json) para abordar los patrones de acceso 10 (`getInvoiceByInvoiceId`) y 11 (`getPaymentByInvoiceId`), ambos relacionados con `invoice`. Aunque se trata de dos patrones de acceso diferentes, se realizan con la misma condición clave. `Payments` se definen como un atributo con el tipo de datos de asignación en la entidad `invoice`.

**nota**  
`GSI1-PK` y `GSI1-SK` se sobrecargan para almacenar información sobre diferentes entidades, de forma que se puedan servir múltiples patrones de acceso desde el mismo GSI. Para obtener más información sobre la sobrecarga de GSI, consulte [Sobrecarga de índices secundarios globales en DynamoDB](bp-gsi-overloading.md).

Para abordar los patrones de acceso 10 y 11, realice una consulta de `GSI1` con `GSI1-PK=invoiceId` y `GSI1-SK=invoiceId`.

**GSI1:**

![\[Diseño de GSI con invoiceId como partición y clave de clasificación para obtener la factura y el pago por ID de factura.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-10-Step9.png)


**Paso 10: Abordar patrones de acceso 12 (`getShipmentDetailsByShipmentId`) y 13 (`getShipmentByWarehouseId`)**

Importe [AnOnlineShop\$112.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_12.json) para abordar los patrones de acceso 12 (`getShipmentDetailsByShipmentId`) y 13 (`getShipmentByWarehouseId`). 

Observe que se agregan entidades `shipmentItem` a la colección de elementos de *pedido* en la tabla base para poder recuperar todos los detalles sobre un pedido en una sola operación de consulta.

**Tabla base:**

![\[Diseño de tabla con la entidad shipmentItem para la recopilación de artículos del pedido para obtener todos los detalles del pedido.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-11-Step10.png)


Las claves de partición y clasificación de `GSI1` ya se han utilizado para modelar una relación de uno a varios entre `shipment` y `shipmentItem`. Para abordar el patrón de acceso 12 (`getShipmentDetailsByShipmentId`), realice una consulta de `GSI1` con `GSI1-PK=shipmentId` y `GSI1-SK=shipmentId`.

**GSI1:**

![\[Diseño de GSI1 con shipmentID como partición y clave de clasificación para obtener los detalles del envío por ID de envío.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-12-Step10-GSI.png)


Tendremos que crear otro GSI (`GSI2`) para modelar la nueva relación de uno a varios entre `warehouse` y `shipment` para el patrón de acceso 13 (`getShipmentByWarehouseId`). Para abordar este patrón de acceso, realice una consulta de `GSI2` con `GSI2-PK=warehouseId` y `GSI2-SK begins_with “sh#”`.

**GSI2:**

![\[Diseño de GSI2 con warehouseId y shipmentId como particiones y claves de clasificación para obtener los envíos por almacén.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-13-Step10-GSI2.png)


**Paso 11: Abordar patrones de acceso 14 (`getProductInventoryByWarehouseId`), 15 (`getInvoiceByCustomerIdForDateRange`) y 16 (`getProductsByCustomerIdForDateRange`)**

Importe [AnOnlineShop\$113.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_13.json) para agregar los datos relacionados con el siguiente conjunto de patrones de acceso. Para abordar el patrón de acceso 14 (`getProductInventoryByWarehouseId`), realice una consulta de `GSI2` con `GSI2-PK=warehouseId` y `GSI2-SK begins_with “p#”`.

**GSI2:**

![\[Diseño de GSI2 con warehouseId y productId como claves de partición y clasificación para abordar el patrón de acceso 14.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-14-Step11-GSI2.png)


Para abordar el patrón de acceso 15 (`getInvoiceByCustomerIdForDateRange`), realice una consulta de `GSI2` con `GSI2-PK=customerId` y `GSI2-SK between (i#date1, i#date2)`.

**GSI2:**

![\[Diseño de GSI2 con customerId y rango de fechas de la factura como partición y claves de clasificación para abordar el patrón de acceso 15.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-15-Step11-GSI2.png)


Para abordar el patrón de acceso 16 (`getProductsByCustomerIdForDateRange`), realice una consulta de `GSI2` con `GSI2-PK=customerId` y `GSI2-SK between (p#date1, p#date2)`.

**GSI2:**

![\[Diseño de GSI2 con customerId y rango de fechas del producto como partición y claves de clasificación para abordar el patrón de acceso 16\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-16-Step11-GSI2.png)


**nota**  
En [NoSQL Workbench](workbench.md), las *facetas* representan los diferentes patrones de acceso a los datos de una aplicación para DynamoDB. Las facetas le permiten ver un subconjunto de datos de una tabla, sin tener que ver registros que no cumplen las restricciones de la faceta. Las facetas se consideran una herramienta visual de modelado de datos y no existen como un constructo utilizable en DynamoDB, ya que son puramente una ayuda para modelar patrones de acceso.   
Importe [AnOnlineShop\$1facets.json](https://github.com/aws-samples/amazon-dynamodb-design-patterns/blob/master/examples/an-online-shop/json/AnOnlineShop_facets.json) para ver las facetas de este caso de uso.

En la tabla siguiente se resumen todos los patrones de acceso y cómo los aborda el diseño del esquema:


| Patrón de acceso | Tabla base/GSI/LSI | Operación | Valor de clave de partición | Valor de la clave de clasificación | 
| --- | --- | --- | --- | --- | 
| getCustomerByCustomerId | Tabla de base | GetItem |  PK=customerId | SK=customerId | 
| getProductByProductId | Tabla de base | GetItem |  PK=productId | SK=productId | 
| getWarehouseByWarehouseId | Tabla de base | GetItem |  PK=warehouseId | SK=warehouseId | 
| getProductInventoryByProductId | Tabla de base | Consultar |  PK=productId | SK begins\$1with “w\$1” | 
| getOrderDetailsByOrderId | Tabla de base | Consultar |  PK=orderId |  | 
| getProductByOrderId | Tabla de base | Consultar |  PK=orderId | SK begins\$1with “p\$1” | 
| getInvoiceByOrderId |  Tabla de base | Consultar |  PK=orderId | SK begins\$1with “i\$1” | 
| getShipmentByOrderId |  Tabla de base | Consultar |  PK=orderId | SK begins\$1with “sh\$1” | 
| getOrderByProductIdForDateRange |  GSI1 | Consultar |  PK=productId | SK between date1 and date2 | 
| getInvoiceByInvoiceId |  GSI1 | Consultar |  PK=invoiceId | SK=invoiceId | 
| getPaymentByInvoiceId |  GSI1 | Consultar |  PK=invoiceId | SK=invoiceId | 
| getShipmentDetailsByShipmentId |  GSI1 | Consultar |  PK=shipmentId | SK=shipmentId | 
| getShipmentByWarehouseId |  GSI2 | Consultar |  PK=warehouseId | SK begins\$1with “sh\$1” | 
| getProductInventoryByWarehouseId |  GSI2 | Consultar |  PK=warehouseId | SK begins\$1with “p\$1” | 
| getInvoiceByCustomerIdForDateRange |  GSI2 | Consultar |  PK=customerId | SK between i\$1date1 and i\$1date2 | 
| getProductsByCustomerIdForDateRange |  GSI2 | Consultar |  PK=customerId | SK between p\$1date1 and p\$1date2 | 

### Esquema final de la tienda en línea
<a name="data-modeling-schema-online-store-final-schema"></a>

Estos son los diseños finales del esquema. Para descargar este diseño de esquema como un archivo JSON, consulte [Patrones de diseño de DynamoDB](https://github.com/aws-samples/aws-dynamodb-examples/tree/master/schema_design/SchemaExamples) en GitHub.

**Tabla base**

![\[Esquema final de la tabla base para una tienda en línea con atributos, como EntityName y Nombre.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-17-Final-BaseTable.png)


**GSI1**

![\[Esquema de GSI1 final para una tabla base de tienda en línea con atributos, como EntityName.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-18-Final-GSI1.png)


**GSI2**

![\[Esquema de GSI2 final para una tabla base de tienda en línea con atributos, como EntityName.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/DataModeling/OnlineShop-19-Final-GSI2.png)


## Uso de NoSQL Workbench con este diseño de esquema
<a name="data-modeling-schema-online-shop-nosql"></a>

Puede importar este esquema final en [NoSQL Workbench](workbench.md), una herramienta visual que proporciona características de modelado de datos, visualización de datos y desarrollo de consultas para DynamoDB, a fin de explorar y editar más a fondo el nuevo proyecto. Para comenzar, siga estos pasos:

1. Descargue NoSQL Workbench. Para obtener más información, consulte [Descargar NoSQL Workbench para DynamoDB](workbench.settingup.md).

1. Descargue el archivo de esquema JSON que se muestra anteriormente, que ya está en el formato de modelo NoSQL Workbench.

1. Importe el archivo de esquema JSON en NoSQL Workbench. Para obtener más información, consulte [Importación de un modelo de datos existente](workbench.Modeler.ImportExisting.md). 

1. Una vez que haya importado en NOSQL Workbench, podrá editar el modelo de datos. Para obtener más información, consulte [Edición de un modelo de datos existente](workbench.Modeler.Edit.md).

# Prácticas recomendadas para modelar datos relacionales en DynamoDB
<a name="bp-relational-modeling"></a>

Esta sección proporciona las prácticas recomendadas para modelar datos relacionales en Amazon DynamoDB. En primer lugar, presentamos los conceptos tradicionales de modelado de datos. A continuación, describimos las ventajas de utilizar DynamoDB frente a los sistemas tradicionales de administración de bases de datos relacionales: cómo elimina la necesidad de realizar operaciones JOIN y reduce la sobrecarga. 

A continuación explicamos cómo diseñar una tabla de DynamoDB que se escale de forma eficiente. Por último, ofrecemos un ejemplo de cómo modelar datos relacionales en DynamoDB.

**Topics**
+ [Modelos tradicionales de bases de datos relacionales](#SQLtoNoSQL.relational-modeling2)
+ [Cómo DynamoDB elimina la necesidad de las operaciones JOIN](#bp-relational-modeling-joins)
+ [Cómo las transacciones de DynamoDB eliminan la sobrecarga del proceso de escritura](#bp-relational-modeling-transactions)
+ [Primeros pasos para modelar datos relacionales en DynamoDB](bp-modeling-nosql.md)
+ [Ejemplo de modelado de datos relacionales en DynamoDB](bp-modeling-nosql-B.md)

## Modelos tradicionales de bases de datos relacionales
<a name="SQLtoNoSQL.relational-modeling2"></a>

Un sistema tradicional de administración de bases de datos relacionales (RDBMS) almacena los datos en una estructura relacional normalizada. El objetivo del modelo de datos relacional es reducir la duplicación de datos (mediante la normalización) para respaldar la integridad referencial y reducir las anomalías en los datos. 

El siguiente esquema es un ejemplo de modelo de datos relacional para una aplicación genérica de entrada de pedidos. La aplicación admite un esquema de recursos humanos que respalda los sistemas operativos y de apoyo empresarial de un fabricante teórico.

![\[Ejemplo de esquema de RDBMS.\]](http://docs.aws.amazon.com/es_es/amazondynamodb/latest/developerguide/images/RDBMS.png)


Como servicio de base de datos no relacional, DynamoDB ofrece muchas ventajas sobre los sistemas tradicionales de administración de bases de datos relacionales. 

## Cómo DynamoDB elimina la necesidad de las operaciones JOIN
<a name="bp-relational-modeling-joins"></a>

Un sistema RDBMS utiliza un lenguaje de consulta estructurado (SQL) para devolver los datos a la aplicación. Debido a la normalización del modelo de datos, estas consultas suelen requerir la utilización del operador `JOIN` para combinar datos de una o varias tablas.

Por ejemplo, para generar una lista de pedidos de compra ordenados por la cantidad de existencias en todos los almacenes que puede enviar cada elemento, podría emitir la siguiente consulta SQL en el esquema anterior.

```
SELECT * FROM Orders
  INNER JOIN Order_Items ON Orders.Order_ID = Order_Items.Order_ID
  INNER JOIN Products ON Products.Product_ID = Order_Items.Product_ID
  INNER JOIN Inventories ON Products.Product_ID = Inventories.Product_ID
  ORDER BY Quantity_on_Hand DESC
```

Las consultas SQL de este tipo pueden proporcionar una API flexible para obtener acceso a los datos, pero requieren una gran cantidad de procesamiento. Cada unión de la consulta aumenta su complejidad en tiempo de ejecución, porque los datos de cada tabla deben prepararse y, a continuación, reunirse para devolver el conjunto de resultados. 

Otros factores que pueden influir en el tiempo que tardan en ejecutarse las consultas son el tamaño de las tablas y si las columnas que se unen tienen índices. La consulta anterior inicia consultas complejas en varias tablas y, a continuación, ordena el conjunto de resultados.

En la esencia del modelado de datos NoSQL se encuentra la eliminación de la necesidad de `JOINs`. Ese es el motivo por el que creamos DynamoDB para que fuera compatible con Amazon.com y, por eso, DynamoDB puede ofrecer un rendimiento coherente a cualquier escala. Dada la complejidad en tiempo de ejecución de las consultas SQL y `JOINs`, el rendimiento del RDBMS no es constante a escala. Esto provoca problemas de rendimiento a medida que crecen las aplicaciones de los clientes.

Aunque la normalización de los datos reduce la cantidad de datos almacenados en el disco, a menudo los recursos más limitados que repercuten en el rendimiento son el tiempo de CPU y la latencia de red. 

DynamoDB se creó para minimizar ambas restricciones mediante la eliminación de `JOINs` (y el fomento de la desnormalización de los datos) y la optimización de la arquitectura de base de datos para responder completamente a la consulta de una aplicación con una única solicitud a un elemento. Estas cualidades permiten a DynamoDB ofrecer un rendimiento de un solo dígito en milisegundos a cualquier escala. Esto se debe a que la complejidad del tiempo de ejecución de las operaciones de DynamoDB es constante, independientemente del tamaño de los datos, para los patrones de acceso habituales.

## Cómo las transacciones de DynamoDB eliminan la sobrecarga del proceso de escritura
<a name="bp-relational-modeling-transactions"></a>

Otro factor que puede ralentizar un sistema RDBMS es el uso de transacciones para escribir en un esquema normalizado. Como se muestra en el ejemplo, las estructuras de datos relacionales que se utilizan en la mayoría de aplicaciones de procesamiento de transacciones online (OLTP) deben dividirse y distribuirse por varias tablas lógicas cuando se almacenan en un sistema RDBMS. 

Por tanto, se necesita un marco de transacciones compatible con ACID que evite las condiciones de carrera y los problemas de integridad de datos que podrían darse si una aplicación intentara leer un objeto que se estuviera escribiendo en ese momento. Un marco de transacciones de este tipo, cuando se combina con un esquema relacional, puede agregar una sobrecarga significativa al proceso de escritura.

La implementación de transacciones en DynamoDB prohíbe los problemas comunes de escalado que se encuentran con un RDBMS. DynamoDB lo hace emitiendo una transacción como una única llamada a la API y limitando el número de elementos a los que se puede acceder en esa única transacción. Las transacciones de larga duración pueden causar problemas operativos al mantener bloqueados los datos durante mucho tiempo o de forma perpetua, porque la transacción nunca se cierra. 

Para evitar estos problemas en DynamoDB, las transacciones se implementaron con dos operaciones de la API distintas: `TransactWriteItems` y `TransactGetItems`. Estas operaciones de la API no tienen la semántica de inicio y fin que es común en un sistema RDBMS. Además, DynamoDB tiene un límite de acceso de 100 elementos en una transacción para evitar de forma similar las transacciones de larga duración. Para obtener más información sobre las transacciones de DynamoDB, consulte [Uso de transacciones](transactions.md).

Por estos motivos, cuando su empresa requiere una respuesta de baja latencia ante consultas con mucho tráfico, suele aportar más ventaja el uso de un sistema NoSQL tanto desde un punto de vista técnico como económico. Amazon DynamoDB ayuda a resolver los problemas que limitan la escalabilidad del sistema relacional evitándolos.

El rendimiento de un sistema RDBMS no suele escalar bien por los siguientes motivos:
+ Utiliza uniones caras para generar las vistas necesarias con los resultados de la consulta.
+ Normalizan los datos y los guardan en varias tablas que requieren muchas consultas para escribir en el disco.
+ Normalmente, hay que sumar los costos de desempeño de un sistema de transacciones compatible con ACID.

DynamoDB escala bien por los siguientes motivos:
+ La flexibilidad del esquema permite que DynamoDB pueda almacenar datos jerárquicos complejos en un solo elemento.
+ El diseño de la clave compuesta permite almacenar elementos relacionados próximos entre sí en la misma tabla.
+ Las transacciones se realizan en una sola operación. El límite para el número de elementos a los que se puede acceder es de 100, para evitar operaciones de larga duración.

Las consultas que se realizan en el almacén de datos son mucho más sencillas y suelen tener la forma siguiente:

```
SELECT * FROM Table_X WHERE Attribute_Y = "somevalue"
```

DynamoDB trabaja mucho menos para devolver los datos solicitados que el sistema RDBMS del ejemplo anterior.

# Primeros pasos para modelar datos relacionales en DynamoDB
<a name="bp-modeling-nosql"></a>

**nota**  
El diseño NoSQL requiere un modo de pensar distinto al diseño de RDBMS. En un sistema RDBMS, puede crear un modelo de datos normalizados sin pensar en los patrones de acceso. Posteriormente, podrá ampliar este modelo cuando surjan nuevos requisitos sobre preguntas y consultas. Por el contrario, en Amazon DynamoDB, no debe empezar a diseñar su esquema hasta que no sepa las preguntas que debe responder. Es absolutamente esencial conocer los problemas del negocio y los costos iniciales de los casos de uso de la aplicación.

Si desea comenzar a diseñar una tabla de DynamoDB que escale efectivamente, debe realizar primero varios pasos para identificar los patrones de acceso requeridos por los sistemas de ayuda de operaciones y de la actividad (OSS/BSS) que deben admitirse:
+ En el caso de las nuevas aplicaciones, revise los casos de usuario para determinar las actividades y los objetivos. Documente los diferentes casos de uso que ha identificado y analice los patrones de acceso que requieren.
+ En las aplicaciones existentes, analice los registros de consultas para saber cuántas personas utilizan actualmente el sistema y cuáles son los patrones de acceso de claves.

Tras completar este proceso, debería tener una lista similar a la siguiente:


**Patrones de acceso para la aplicación de entrada de pedidos**  

| Patrón número | Descripción de patrón de acceso | 
| --- | --- | 
| 1 | Buscar detalles de empleado por ID de empleado | 
| 2 | Consultar detalles de empleado por nombre de empleado | 
| 3 | Encontrar los números de teléfono de un empleado | 
| 4 | Encontrar los números de teléfono de un cliente | 
| 5 | Obtener los pedidos de los clientes dentro del rango de fechas | 
| 6 | Mostrar todos los pedidos abiertos dentro del rango de fechas | 
| 7 | Ver todos los empleados contratados recientemente | 
| 8 | Encontrar a todos los empleados en un almacén | 
| 9 | Obtener todos los artículos del pedido por producto | 
| 10 | Obtener inventarios de productos en todos los almacenes | 
| 11 | Obtener clientes por representante de cuenta | 
| 12 | Obtener pedidos por representante de cuenta | 
| 13 | Obtener empleados con título de trabajo | 
| 14 | Obtener inventario por producto y almacén | 
| 15 | Obtener inventario de productos total | 

En una aplicación real, la lista podría ser mucho más larga. Sin embargo, esta colección representa el rango de complejidad de los patrones de consulta que podría encontrar en un entorno de producción.

Un enfoque moderno del diseño de esquemas de DynamoDB utiliza principios orientados a los agregados, que agrupan los datos en función de los patrones de acceso en lugar de los límites rígidos de las entidades. Este enfoque tiene en cuenta varios patrones de diseño:
+ *Diseño de tabla única*: uso de claves de clasificación compuestas, índices secundarios globales sobrecargados y patrones de listas de adyacencia para almacenar varios tipos de entidades en una tabla.
+ *Diseño de varias tablas*: uso de tablas independientes para las entidades con características operativas independientes y una baja correlación de acceso, con GSI estratégicos para las consultas entre entidades.
+ *Diseño agregado*: incrustación relacionada con datos cuando siempre se accede a ellos de forma conjunta (Pedido \$1 OrderItems) o usar recopilaciones de artículos para identificar relaciones (Producto \$1 Inventario).

La elección entre estos enfoques depende de los patrones de acceso específicos, las características de los datos y los requisitos operativos. Puede utilizar estos elementos para estructurar los datos de forma que una aplicación pueda recuperar todo aquello que necesite para un determinado patrón de acceso realizando una sola consulta en una tabla o índice.

**nota**  
La elección entre el diseño de una sola tabla y de varias tablas depende de sus requisitos específicos. El diseño de una sola tabla funciona bien cuando las entidades tienen una alta correlación de acceso y características operativas similares. Se prefiere el diseño de varias tablas cuando las entidades tienen requisitos operativos independientes, patrones de acceso diferentes o cuando se necesitan límites operativos claros. El ejemplo de esta guía muestra un enfoque de varias tablas con agregación y desnormalización estratégicas.

Para utilizar NoSQL Workbench para DynamoDB como ayuda para visualizar su diseño de clave de partición, consulte [Creación de modelos de datos con NoSQL Workbench](workbench.Modeler.md).

# Ejemplo de modelado de datos relacionales en DynamoDB
<a name="bp-modeling-nosql-B"></a>

En este ejemplo, se describe cómo se modelan los datos relacionales en Amazon DynamoDB. El diseño de las tablas de DynamoDB se corresponde con el esquema relacional de registro de pedidos que se muestra en [Modelos relacionales](bp-relational-modeling.md). Este diseño utiliza varias tablas especializadas en lugar de una sola lista de adyacencias, lo que proporciona límites operativos claros y, al mismo tiempo, aprovecha los GSI estratégicos para atender todos los patrones de acceso de manera eficiente.

El enfoque del diseño utiliza principios orientados a los agregados, que agrupan los datos en función de los patrones de acceso en lugar de los límites rígidos de las entidades. Las principales decisiones de diseño incluyen el uso de tablas independientes para las entidades con una baja correlación de acceso, la incrustación de los datos relacionados cuando siempre se accede a ellos juntos y el uso de recopilaciones de elementos para identificar las relaciones.

Las siguientes tablas y los índices que las acompañan respaldan el esquema de registro de pedidos relacionales:

## Diseño de tabla de empleados
<a name="employee-table-design"></a>

La tabla de empleados almacena la información de los empleados como una sola entidad por elemento, optimizada para las búsquedas directas de los empleados y compatible con múltiples patrones de consulta a través de GSI estratégicos. En esta tabla, se muestra el principio de diseñar tablas independientes para entidades con características operativas independientes y una baja correlación de acceso entre entidades.

La tabla utiliza una clave de partición simple (employee\$1id) sin una clave de clasificación, ya que cada empleado es una entidad distinta. Cuatro GSI permiten realizar consultas eficientes por diferentes atributos:
+ *EmployeeByName GSI*: utiliza la proyección INCLUDE con todos los atributos de los empleados para facilitar la recuperación completa de los detalles de los empleados por nombre, gestiona los posibles nombres duplicados con employee\$1id como clave de clasificación.
+ *EmployeeByWarehouse GSI*: utiliza la proyección INCLUDE solo con los atributos esenciales (name, job\$1title, hire\$1date) para minimizar los costes de almacenamiento y, al mismo tiempo, permitir las consultas basadas en el almacén.
+ *EmployeeByJobTitle GSI*: permite realizar consultas basadas en roles con la proyección INCLUDE para la elaboración de informes y el análisis de la organización.
+ *EmployeeByHireDate GSI*: utiliza un valor de clave de partición estática “EMPLOYEE” con hire\$1date como clave de clasificación para permitir consultas eficientes por intervalos de fechas para las contrataciones recientes. Dado que las incorporaciones o actualizaciones de los empleados suelen ser inferiores a 1000 WCU, una sola partición puede gestionar la carga de escritura sin problemas relacionados con las particiones más frecuentes.


**Tabla de empleados: estructura de la tabla base**  

| employee\$1id (PK) | name | phone\$1numbers | warehouse\$1id | job\$1title | hire\$1date | entity\$1type | 
| --- | --- | --- | --- | --- | --- | --- | 
| emp\$1001 | John Smith | [“\$11-555-0101”] | wh\$1sea | Manager | 2024-03-15 | EMPLEADO | 
| emp\$1002 | Jane Doe | [“\$11-555-0102”, “\$11-555-0103”] | wh\$1sea | Asociar | 2025-01-10 | EMPLEADO | 
| emp\$1003 | Bob Wilson | [“\$11-555-0104”] | wh\$1pdx | Asociar | 2025-06-20 | EMPLEADO | 
| emp\$1004 | Alice Brown | [“\$11-555-0105”] | wh\$1pdx | Supervisor | 2023-11-05 | EMPLEADO | 
| emp\$1005 | Charlie Davis | [“\$11-555-0106”] | wh\$1sea | Asociar | 2025-12-01 | EMPLEADO | 


**EmployeeByName GSI: compatibilidad de consultas de nombre de empleado**  

| nombre (GSI-PK) | employee\$1id (GSI-SK) | phone\$1numbers | warehouse\$1id | job\$1title | hire\$1date | 
| --- | --- | --- | --- | --- | --- | 
| Alice Brown | emp\$1004 | [“\$11-555-0105”] | wh\$1pdx | Supervisor | 2023-11-05 | 
| Bob Wilson | emp\$1003 | [“\$11-555-0104”] | wh\$1pdx | Asociar | 2025-06-20 | 
| Charlie Davis | emp\$1005 | [“\$11-555-0106”] | wh\$1sea | Asociar | 2025-12-01 | 
| Jane Doe | emp\$1002 | [“\$11-555-0102”, “\$11-555-0103”] | wh\$1sea | Asociar | 2025-01-10 | 
| John Smith | emp\$1001 | [“\$11-555-0101”] | wh\$1sea | Manager | 2024-03-15 | 


**EmployeeByWarehouse GSI: compatibilidad de consultas de almacén**  

| warehouse\$1id (GSI-PK) | employee\$1id (GSI-SK) | name | job\$1title | hire\$1date | 
| --- | --- | --- | --- | --- | 
| wh\$1pdx | emp\$1003 | Bob Wilson | Asociar | 2025-06-20 | 
| wh\$1pdx | emp\$1004 | Alice Brown | Supervisor | 2023-11-05 | 
| wh\$1sea | emp\$1001 | John Smith | Manager | 2024-03-15 | 
| wh\$1sea | emp\$1002 | Jane Doe | Asociar | 2025-01-10 | 
| wh\$1sea | emp\$1005 | Charlie Davis | Asociar | 2025-12-01 | 


**EmployeeByJobTitle GSI: compatibilidad de consultas de títulos de trabajo**  

| job\$1title (GSI-PK) | employee\$1id (GSI-SK) | name | warehouse\$1id | hire\$1date | 
| --- | --- | --- | --- | --- | 
| Asociar | emp\$1002 | Jane Doe | wh\$1sea | 2025-01-10 | 
| Asociar | emp\$1003 | Bob Wilson | wh\$1pdx | 2025-06-20 | 
| Asociar | emp\$1005 | Charlie Davis | wh\$1sea | 2025-12-01 | 
| Manager | emp\$1001 | John Smith | wh\$1sea | 2024-03-15 | 
| Supervisor | emp\$1004 | Alice Brown | wh\$1pdx | 2023-11-05 | 


**EmployeeByHireDate GSI: compatibilidad de consultas de contrataciones recientes**  

| entity\$1type (GSI-PK) | hire\$1date (GSI-SK) | employee\$1id | name | warehouse\$1id | 
| --- | --- | --- | --- | --- | 
| EMPLEADO | 2023-11-05 | emp\$1004 | Alice Brown | wh\$1pdx | 
| EMPLEADO | 2024-03-15 | emp\$1001 | John Smith | wh\$1sea | 
| EMPLEADO | 2025-01-10 | emp\$1002 | Jane Doe | wh\$1sea | 
| EMPLEADO | 2025-06-20 | emp\$1003 | Bob Wilson | wh\$1pdx | 
| EMPLEADO | 2025-12-01 | emp\$1005 | Charlie Davis | wh\$1sea | 

## Diseño de tabla de clientes
<a name="customer-table-design"></a>

La tabla de clientes mantiene la información de los clientes con la desnormalización estratégica de account\$1rep\$1id para permitir consultas eficientes de los representantes de las cuentas. Esta opción de diseño reduce una pequeña sobrecarga de almacenamiento en beneficio del rendimiento de las consultas, lo que elimina la necesidad de unir los datos de los clientes y los de los representantes de la cuenta.

La tabla admite varios números de teléfono por cliente mediante un atributo de lista, lo que demuestra la flexibilidad del esquema de DynamoDB. El GSI único permite los flujos de trabajo de los representantes de cuentas:
+ *CustomerByAccountRep GSI*: utiliza la proyección INCLUDE con los atributos de nombre y correo electrónico para facilitar la administración de clientes del representante de cuentas sin necesidad de recuperar todos los registros de los clientes.


**Tabla de clientes: estructura de la tabla base**  

| customer\$1id (PK) | name | phone\$1numbers | correo electrónico | account\$1rep\$1id | 
| --- | --- | --- | --- | --- | 
| cust\$1001 | Acme Corp | [“\$11-555-1001”] | contact@acme.com | rep\$1001 | 
| cust\$1002 | TechStart Inc | [“\$11-555-1002”, “\$11-555-1003”] | info@techstart.com | rep\$1001 | 
| cust\$1003 | Global Traders | [“\$11-555-1004”] | sales@globaltraders.com | rep\$1002 | 
| cust\$1004 | BuildRight LLC | [“\$11-555-1005”] | orders@buildright.com | rep\$1002 | 
| cust\$1005 | FastShip Co | [“\$11-555-1006”] | support@fastship.com | rep\$1003 | 


**CustomerByAccountRep GSI: compatibilidad de consultas de representantes de cuentas**  

| account\$1rep\$1id (GSI-PK) | customer\$1id (GSI-SK) | name | correo electrónico | 
| --- | --- | --- | --- | 
| rep\$1001 | cust\$1001 | Acme Corp | contact@acme.com | 
| rep\$1001 | cust\$1002 | TechStart Inc | info@techstart.com | 
| rep\$1002 | cust\$1003 | Global Traders | sales@globaltraders.com | 
| rep\$1002 | cust\$1004 | BuildRight LLC | orders@buildright.com | 
| rep\$1003 | cust\$1005 | FastShip Co | support@fastship.com | 

## Diseño de tabla de pedidos
<a name="order-table-design"></a>

La tabla de pedidos utiliza una partición vertical con elementos independientes para los encabezados de los pedidos y los elementos de los pedidos. Este diseño permite realizar consultas eficientes basadas en el producto y, al mismo tiempo, mantener todos los componentes del pedido dentro de la misma partición para un acceso eficiente. Cada pedido consta de varios elementos:
+ *Encabezado del pedido*: contiene los metadatos del pedido con PK=order\$1id, SK=order\$1id
+ *Elementos del pedido*: elementos de línea individuales con PK=order\$1id, SK=product\$1id, lo que permite realizar consultas directas de productos

**nota**  
Este enfoque de partición vertical compensa la simplicidad de los elementos de pedido incrustados en favor de una mayor flexibilidad de consulta. Cada elementos del pedido se convierte en un elemento independiente de DynamoDB, lo que permite realizar consultas eficientes basadas en el producto y, al mismo tiempo, mantener todos los datos del pedido en la misma partición para poder recuperarlos de forma eficaz en una sola solicitud.

La tabla incluye la desnormalización estratégica de account\$1rep\$1id (un duplicado de la tabla de clientes) para permitir consultas directas a los representantes de las cuentas sin necesidad de buscar a los clientes. Para escenarios de escritura de alto rendimiento, los pedidos ABIERTOS incluyen los atributos de estado y partición para permitir la fragmentación de escritura en varias particiones.

Cuatro GSI admiten diferentes patrones de consulta con proyecciones optimizadas:
+ *OrderByCustomerDate GSI*: utiliza la proyección INCLUDE con el resumen del pedido y los detalles de los elementos para respaldar el historial de pedidos de los clientes con un filtrado por intervalos de fechas
+ *OpenOrdersByDate GSI (disperso, particionado)*: utiliza una clave de partición con varios atributos (estado \$1 partición) con 5 particiones para distribuir 5000 WPS (escrituras por segundo) entre las particiones (1000 WPS cada una, lo que equivale al límite de 1000 WCU por partición de DynamoDB). Solo indexa los pedidos ABIERTOS (el 20 % del total), lo que puede ayudar a reducir los costos de almacenamiento de GSI. Requiere consultas paralelas en las 5 particiones con la fusión de los resultados del cliente
+ *OrderByAccountRep GSI*: utiliza la proyección INCLUDE con los atributos del resumen del pedido para respaldar los flujos de trabajo representativos de las cuentas sin tener todos los detalles del pedido
+ *ProductInOrders GSI*: a partir de registros de OrderItem (PK=order\$1id, SK=product\$1id), este GSI permite realizar consultas para encontrar todos los pedidos que contengan un producto específico. Usa la proyección INCLUDE con el contexto del pedido (customer\$1id, order\$1date, quantity) para el análisis de la demanda de productos


**Tabla de pedidos: estructura de la tabla base (partición vertical)**  

| PK | SK | customer\$1id | order\$1date | status | account\$1rep\$1id | quantity | precio | partición | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| ord\$1001 | ord\$1001 | cust\$1001 | 2025-11-15 | CLOSED | rep\$1001 |  |  |  | 
| ord\$1001 | prod\$1100 |  |  |  |  | 5 | 25.00 |  | 
| ord\$1002 | ord\$1002 | cust\$1001 | 2025-12-20 | OPEN | rep\$1001 |  |  | 0 | 
| ord\$1002 | prod\$1101 |  |  |  |  | 10 | 15.00 |  | 
| ord\$1003 | ord\$1003 | cust\$1002 | 2026-01-05 | OPEN | rep\$1001 |  |  | 2 | 
| ord\$1003 | prod\$1100 |  |  |  |  | 3 | 25.00 |  | 


**OrderByCustomerDate GSI: compatibilidad de consultas de pedidos de clientes**  

| customer\$1id (GSI-PK) | order\$1date (GSI-SK) | order\$1id | status | total\$1amount | order\$1items | partición | 
| --- | --- | --- | --- | --- | --- | --- | 
| cust\$1001 | 2025-11-15 | ord\$1001 | CLOSED | 225.00 | [\$1product\$1id: "prod\$1100", qty: 5\$1] |  | 
| cust\$1001 | 2025-12-20 | ord\$1002 | OPEN | 150.00 | [\$1product\$1id: "prod\$1101", qty: 10\$1] | 0 | 
| cust\$1002 | 2026-01-05 | ord\$1003 | OPEN | 175.00 | [\$1product\$1id: "prod\$1100", qty: 3\$1] | 2 | 
| cust\$1003 | 2025-10-10 | ord\$1004 | CLOSED | 250.00 | [\$1product\$1id: "prod\$1101", qty: 5\$1] |  | 
| cust\$1004 | 2026-01-03 | ord\$1005 | OPEN | 200.00 | [\$1product\$1id: "prod\$1100", qty: 20\$1] | 1 | 


**OpenOrdersByDate GSI (disperso, particionado): compatibilidad de consultas de pedidos abiertos de alto rendimiento**  

| estado (GSI-PK-1) | partición (GSI-PK-2) | order\$1date (SK) | order\$1id | customer\$1id | account\$1rep\$1id | order\$1items | total\$1amount | 
| --- | --- | --- | --- | --- | --- | --- | --- | 
| OPEN | 0 | 2025-12-20 | ord\$1002 | cust\$1001 | rep\$1001 | [\$1product\$1id: "prod\$1101", qty: 10\$1] | 150.00 | 
| OPEN | 1 | 2026-01-03 | ord\$1005 | cust\$1004 | rep\$1002 | [\$1product\$1id: "prod\$1100", qty: 20\$1] | 200.00 | 
| OPEN | 2 | 2026-01-05 | ord\$1003 | cust\$1002 | rep\$1001 | [\$1product\$1id: "prod\$1100", qty: 3\$1] | 175.00 | 


**OrderByAccountRep GSI: compatibilidad de consultas de pedidos de representantes de cuentas**  

| account\$1rep\$1id (GSI-PK) | order\$1date (GSI-SK) | order\$1id | customer\$1id | status | total\$1amount | 
| --- | --- | --- | --- | --- | --- | 
| rep\$1001 | 2025-11-15 | ord\$1001 | cust\$1001 | CLOSED | 225.00 | 
| rep\$1001 | 2025-12-20 | ord\$1002 | cust\$1001 | OPEN | 150.00 | 
| rep\$1001 | 2026-01-05 | ord\$1003 | cust\$1002 | OPEN | 175.00 | 
| rep\$1002 | 2025-10-10 | ord\$1004 | cust\$1003 | CLOSED | 250.00 | 
| rep\$1002 | 2026-01-03 | ord\$1005 | cust\$1004 | OPEN | 200.00 | 


**ProductInOrders GSI: compatibilidad de consultas de pedidos de productos**  

| product\$1id (GSI-PK) | order\$1id (GSI-SK) | customer\$1id | order\$1date | quantity | 
| --- | --- | --- | --- | --- | 
| prod\$1100 | ord\$1001 | cust\$1001 | 2025-11-15 | 5 | 
| prod\$1100 | ord\$1003 | cust\$1002 | 2026-01-05 | 3 | 
| prod\$1101 | ord\$1002 | cust\$1001 | 2025-12-20 | 10 | 

## Diseño de tabla de productos
<a name="product-table-design"></a>

La tabla de productos utiliza el patrón de recopilación de elementos para almacenar los metadatos del producto y los datos de inventario en la misma partición. Este diseño aprovecha la relación de identificación entre los productos y el inventario: el inventario no puede existir sin un producto principal. El uso de PK=product\$1id con SK=product\$1id para los metadatos del producto y SK=warehouse\$1id para los elementos del inventario elimina la necesidad de tener una tabla de inventario y un GSI independientes, lo que reduce los costos en aproximadamente un 50 %.

Este patrón permite realizar consultas eficientes tanto para el inventario de almacén individual (GetItem con clave compuesta) como para todo el inventario de almacén de un producto (consulta en clave de partición). El atributo total\$1inventory del elemento de metadatos del producto proporciona una agregación desnormalizada para realizar búsquedas rápidas del inventario total.


**Tabla de productos: estructura de la tabla base (patrón de recopilación de elementos)**  

| product\$1id (PK) | warehouse\$1id (SK) | product\$1name | categoría | unit\$1price | inventory\$1quantity | total\$1inventory | 
| --- | --- | --- | --- | --- | --- | --- | 
| prod\$1100 | prod\$1100 | Widget A | Hardware de  | 25.00 |  | 500 | 
| prod\$1100 | wh\$1sea |  |  |  | 200 |  | 
| prod\$1100 | wh\$1pdx |  |  |  | 150 |  | 
| prod\$1100 | wh\$1atl |  |  |  | 150 |  | 
| prod\$1101 | prod\$1101 | Gadget B | Electronics | 50.00 |  | 300 | 
| prod\$1101 | wh\$1sea |  |  |  | 100 |  | 
| prod\$1101 | wh\$1pdx |  |  |  | 200 |  | 

Cada tabla está diseñada con índices secundarios globales (GSI) específicos para respaldar los patrones de acceso requeridos de manera eficiente. El diseño utiliza principios orientados a los agregados con una desnormalización estratégica y una indexación dispersa para optimizar tanto el rendimiento como los costos.

Las principales optimizaciones de diseño incluyen:
+ *GSI disperso*: OpenOrdersByDate solo indexa los pedidos ABIERTOS (20 % del total), que puede ayudar a reducir los costos de almacenamiento de GSI
+ *Patrón de recolección de elementos*: la tabla de productos almacena el inventario mediante PK=product\$1id y SK=warehouse\$1id para eliminar la tabla de inventario independiente
+ *Agregación de pedido \$1 OrderItems*: incrustado como un solo elemento debido a una correlación de acceso del 100 %
+ *Desnormalización estratégica*: account\$1rep\$1id duplicado en la tabla de pedidos para facilitar las consultas

Por último, puede volver a consultar los patrones de acceso que se definieron anteriormente. En la tabla siguiente, se muestra cómo se admite cada patrón de acceso de manera eficiente mediante el diseño de varias tablas con GSI estratégicos. Cada patrón utiliza búsquedas de claves directas o consultas de GSI únicas, lo que evita análisis costosos y proporciona un rendimiento coherente a cualquier escala.


| S. No. | Patrones de acceso | Condiciones de la consulta | 
| --- | --- | --- | 
|  1  |  Buscar detalles de empleado por ID de empleado  |  Tabla de empleados: GetItem(employee\$1id="emp\$1001")  | 
|  2  |  Consultar detalles de empleado por nombre de empleado  |  EmployeeByName GSI: Query(name="John Smith")  | 
|  3  |  Encontrar los números de teléfono de un empleado  |  Tabla de empleados: GetItem(employee\$1id="emp\$1001")  | 
|  4  |  Encontrar los números de teléfono de un cliente  |  Tabla de clientes: GetItem(customer\$1id="cust\$1001")  | 
|  5  |  Obtener los pedidos de los clientes dentro del rango de fechas  |  OrderByCustomerDate GSI: Query(customer\$1id="cust\$1001", order\$1date BETWEEN "2025-01-01" AND "2025-12-31")  | 
|  6  |  Mostrar todos los pedidos abiertos dentro del rango de fechas  |  OpenOrdersByDate GSI: consulte 5 particiones en paralelo con PK de varios atributos (status="OPEN" \$1 shard=0-4), SK=order\$1date BETWEEN "2025-01-01" AND "2025-12-31", resultados de combinación  | 
|  7  |  Ver todos los empleados contratados recientemente  |  EmployeeByHireDate GSI: Query(entity\$1type="EMPLOYEE", hire\$1date >= "2025-01-01")  | 
|  8  |  Encontrar a todos los empleados en un almacén  |  EmployeeByWarehouse GSI: Query(warehouse\$1id="wh\$1sea")  | 
|  9  |  Obtener todos los artículos del pedido por producto  |  ProductInOrders GSI: Query(product\$1id="prod\$1100")  | 
|  10  |  Obtener inventarios de productos en todos los almacenes  |  Tabla de productos: Query(product\$1id="prod\$1100")  | 
|  11  |  Obtener clientes por representante de cuenta  |  CustomerByAccountRep GSI: Query(account\$1rep\$1id="rep\$1001")  | 
|  12  |  Obtener pedidos por representante de cuenta  |  OrderByAccountRep GSI: Query(account\$1rep\$1id="rep\$1001")  | 
|  13  |  Obtener empleados con título de trabajo  |  EmployeeByJobTitle GSI: Query(job\$1title="Manager")  | 
|  14  |  Obtener inventario por producto y almacén  |  Tabla de productos: GetItem(product\$1id="prod\$1100", warehouse\$1id="wh\$1sea")  | 
|  15  |  Obtener inventario de productos total  |  Tabla de productos: GetItem(product\$1id="prod\$1100", warehouse\$1id="prod\$1100")  | 