├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── examples ├── an-online-shop ├── README.md ├── json │ ├── AnOnlineShop_1.json │ ├── AnOnlineShop_10.json │ ├── AnOnlineShop_11.json │ ├── AnOnlineShop_12.json │ ├── AnOnlineShop_13.json │ ├── AnOnlineShop_14.json │ ├── AnOnlineShop_2.json │ ├── AnOnlineShop_3.json │ ├── AnOnlineShop_4.json │ ├── AnOnlineShop_5.json │ ├── AnOnlineShop_6.json │ ├── AnOnlineShop_7.json │ ├── AnOnlineShop_8.json │ ├── AnOnlineShop_9.json │ └── AnOnlineShop_facets.json └── resources │ ├── AnOnlineShopErd.png │ ├── AnOnlineShop_1.png │ ├── AnOnlineShop_2.png │ ├── AnOnlineShop_3.png │ ├── AnOnlineShop_4.png │ ├── AnOnlineShop_5.png │ ├── AnOnlineShop_6.png │ ├── AnOnlineShop_6table.png │ ├── AnOnlineShop_7.png │ ├── AnOnlineShop_8a.png │ ├── AnOnlineShop_8a_table.png │ ├── AnOnlineShop_8b.png │ └── AnOnlineShop_9.png ├── device-state-log ├── README.md ├── aws-cli-commands │ └── aws-cli-dynamodb-commands.txt ├── json │ ├── DeviceStateLog_1.json │ ├── DeviceStateLog_2.json │ ├── DeviceStateLog_3.json │ ├── DeviceStateLog_4.json │ ├── DeviceStateLog_5.json │ ├── DeviceStateLog_6.json │ └── DeviceStateLog_7.json └── resources │ ├── DeviceStateLog_1.png │ ├── DeviceStateLog_2_composite_sk.png │ ├── DeviceStateLog_3.png │ ├── DeviceStateLog_GSI1_1.png │ ├── DeviceStateLog_GSI2.png │ └── DeviceStateLog_Table_GSI2.png └── version-control ├── README.md ├── number-based-version ├── atomic-counters │ ├── README.md │ ├── src │ │ ├── add_equipment │ │ │ ├── main.py │ │ │ └── requirements.txt │ │ ├── add_new_version │ │ │ ├── main.py │ │ │ └── requirements.txt │ │ └── get_latest_version │ │ │ ├── main.py │ │ │ └── requirements.txt │ └── template.yaml ├── dynamodb-streams │ ├── README.md │ ├── src │ │ ├── add_equipment │ │ │ ├── main.py │ │ │ └── requirements.txt │ │ ├── add_new_version │ │ │ ├── main.py │ │ │ └── requirements.txt │ │ ├── get_latest_version │ │ │ ├── main.py │ │ │ └── requirements.txt │ │ └── update_latest_version │ │ │ ├── main.py │ │ │ └── requirements.txt │ └── template.yaml └── transactional-write │ ├── README.md │ ├── src │ ├── add_equipment │ │ ├── main.py │ │ └── requirements.txt │ ├── add_new_version │ │ ├── main.py │ │ └── requirements.txt │ └── get_latest_version │ │ ├── main.py │ │ └── requirements.txt │ └── template.yaml └── time-based-version ├── README.md ├── src ├── add_equipment │ ├── main.py │ └── requirements.txt ├── add_new_version │ ├── main.py │ └── requirements.txt └── get_latest_version │ ├── main.py │ └── requirements.txt └── template.yaml /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | 3 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 4 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 5 | opensource-codeofconduct@amazon.com with any additional questions or comments. 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon DynamoDB Design Patterns 2 | 3 | This repo contains sample data models and source code to demonstrate design patterns for Amazon DynamoDB. 4 | 5 | ## Examples 6 | 7 | Data models and source code are listed under the `/examples` folder. 8 | - Device State Log - [*Data model*] 9 | - An Online Shop - [*Data model*] 10 | - Implementing version control using Amazon Dynamodb - [*Source code*] 11 | 12 | 13 | ## NoSQL Design 14 | 15 | When designing a data model for Amazon DynamoDB, it is important to understand the use case and requirements, and then identify entities and the relationships between them. One way to illustrate the relations is to draw an Entity Relation Diagram (ERD). It is also recommended to identify the access patterns needed to fulfill the requirements up front and then go through them one by one to store data in such format that the access pattern can be handled. 16 | 17 | It is a good practice to use [NoSQL Workbench for Amazon DynamoDB](#nosql-workbench-for-amazon-dynamodb) when designing and reviewing the data model for an application. Once the data model is completed, the next step is to review and apply any improvements to the data model. A good design is achieved after multiple review iterations. 18 | 19 | In general, maintain as few tables as possible in an Amazon DynamoDB application, and if it suits the use case then store all the entities in a single table. By overloading a table with several entities, the number of network round trips from the application to Amazon DynamoDB can be reduced as each item collection can contain relations between several entities and can be retrieved in one query operation. Item collection refers to item(s) that have the same partition key. It is also a common pattern to overload global secondary indexes (GSI) to handle access patterns that can not be addressed by the table. 20 | 21 | ## NoSQL Workbench for Amazon DynamoDB 22 | 23 | [NoSQL Workbench for Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html) is a cross-platform client-side GUI application for modern database development and operations. NoSQL Workbench is available for Windows, macOS, and Linux. 24 | 25 | The data model including table(s), global secondary indexes and any data populated in the table(s) can be exported in `json` format. This file can be shared within a team and can of course be added to a version control tool in order to keep track of different review versions. The data model can be committed to Amazon DynamoDB in an AWS account or to DynamoDB Local from NoSQL Workbench. 26 | 27 | ## Security 28 | 29 | See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. 30 | 31 | ## License 32 | 33 | This library is licensed under the MIT-0 License. See the [LICENSE](LICENSE) file. 34 | -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_1.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "ModelName": "AnOnlineShop", 4 | "ModelMetadata": { 5 | "Author": "Samaneh Utter", 6 | "DateCreated": "Jun 24, 2020, 04:20 PM", 7 | "DateLastModified": "Jun 24, 2020, 04:28 PM", 8 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 9 | "Version": "1.0" 10 | }, 11 | "DataModel": [ 12 | { 13 | "TableName": "OnlineShop", 14 | "KeyAttributes": { 15 | "PartitionKey": { 16 | "AttributeName": "PK", 17 | "AttributeType": "S" 18 | }, 19 | "SortKey": { 20 | "AttributeName": "SK", 21 | "AttributeType": "S" 22 | } 23 | }, 24 | "NonKeyAttributes": [ 25 | ], 26 | "TableData": [ 27 | ], 28 | "DataAccess": { 29 | "MySql": {} 30 | } 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_10.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Aug 25, 2020, 04:34 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "GSI1-PK", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "GSI1-SK", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Email", 38 | "AttributeType": "S" 39 | }, 40 | { 41 | "AttributeName": "Name", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Detail", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Price", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Address", 54 | "AttributeType": "M" 55 | }, 56 | { 57 | "AttributeName": "Quantity", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Type", 62 | "AttributeType": "S" 63 | }, 64 | { 65 | "AttributeName": "Amount", 66 | "AttributeType": "S" 67 | }, 68 | { 69 | "AttributeName": "Date", 70 | "AttributeType": "S" 71 | }, 72 | { 73 | "AttributeName": "WarehouseId", 74 | "AttributeType": "S" 75 | } 76 | ], 77 | "GlobalSecondaryIndexes": [ 78 | { 79 | "IndexName": "GSI1", 80 | "KeyAttributes": { 81 | "PartitionKey": { 82 | "AttributeName": "GSI1-PK", 83 | "AttributeType": "S" 84 | }, 85 | "SortKey": { 86 | "AttributeName": "GSI1-SK", 87 | "AttributeType": "S" 88 | } 89 | }, 90 | "Projection": { 91 | "ProjectionType": "ALL" 92 | } 93 | } 94 | ], 95 | "TableData": [ 96 | { 97 | "PK": { 98 | "S": "c#12345" 99 | }, 100 | "SK": { 101 | "S": "c#12345" 102 | }, 103 | "EntityType": { 104 | "S": "customer" 105 | }, 106 | "Email": { 107 | "S": "samaneh@example.com" 108 | }, 109 | "Name": { 110 | "S": "Samaneh" 111 | } 112 | }, 113 | { 114 | "PK": { 115 | "S": "c#23456" 116 | }, 117 | "SK": { 118 | "S": "c#23456" 119 | }, 120 | "EntityType": { 121 | "S": "customer" 122 | }, 123 | "Email": { 124 | "S": "kathleen@example.com" 125 | }, 126 | "Name": { 127 | "S": "Kathleen" 128 | } 129 | }, 130 | { 131 | "PK": { 132 | "S": "c#54321" 133 | }, 134 | "SK": { 135 | "S": "c#54321" 136 | }, 137 | "EntityType": { 138 | "S": "customer" 139 | }, 140 | "Email": { 141 | "S": "henrik@example.com" 142 | }, 143 | "Name": { 144 | "S": "Henrik" 145 | } 146 | }, 147 | { 148 | "PK": { 149 | "S": "p#12345" 150 | }, 151 | "SK": { 152 | "S": "p#12345" 153 | }, 154 | "EntityType": { 155 | "S": "product" 156 | }, 157 | "Detail": { 158 | "M": { 159 | "Name": { 160 | "S": "Options Open" 161 | }, 162 | "Description": { 163 | "S": "The latest album" 164 | } 165 | } 166 | }, 167 | "Price": { 168 | "S": "100" 169 | } 170 | }, 171 | { 172 | "PK": { 173 | "S": "p#99887" 174 | }, 175 | "SK": { 176 | "S": "p#99887" 177 | }, 178 | "EntityType": { 179 | "S": "product" 180 | }, 181 | "Detail": { 182 | "M": { 183 | "Name": { 184 | "S": "The Book" 185 | }, 186 | "Description": { 187 | "S": "The best book ever" 188 | } 189 | } 190 | }, 191 | "Price": { 192 | "S": "40" 193 | } 194 | }, 195 | { 196 | "PK": { 197 | "S": "w#12345" 198 | }, 199 | "SK": { 200 | "S": "w#12345" 201 | }, 202 | "EntityType": { 203 | "S": "warehouse" 204 | }, 205 | "Address": { 206 | "M": { 207 | "Country": { 208 | "S": "Sweden" 209 | }, 210 | "County": { 211 | "S": "Vastra Gotaland" 212 | }, 213 | "City": { 214 | "S": "Goteborg" 215 | }, 216 | "Street": { 217 | "S": "MainStreet" 218 | }, 219 | "Number": { 220 | "S": "20" 221 | }, 222 | "ZipCode": { 223 | "S": "41111" 224 | } 225 | } 226 | } 227 | }, 228 | { 229 | "PK": { 230 | "S": "w#12376" 231 | }, 232 | "SK": { 233 | "S": "w#12376" 234 | }, 235 | "EntityType": { 236 | "S": "warehouse" 237 | }, 238 | "Address": { 239 | "M": { 240 | "Country": { 241 | "S": "Sweden" 242 | }, 243 | "County": { 244 | "S": "Vastra Gotaland" 245 | }, 246 | "City": { 247 | "S": "Boras" 248 | }, 249 | "Street": { 250 | "S": "RiverStreet" 251 | }, 252 | "Number": { 253 | "S": "20" 254 | }, 255 | "ZipCode": { 256 | "S": "11111" 257 | } 258 | } 259 | } 260 | }, 261 | { 262 | "PK": { 263 | "S": "p#12345" 264 | }, 265 | "SK": { 266 | "S": "w#12345" 267 | }, 268 | "EntityType": { 269 | "S": "warehouseItem" 270 | }, 271 | "Quantity": { 272 | "S": "50" 273 | } 274 | }, 275 | { 276 | "PK": { 277 | "S": "p#99887" 278 | }, 279 | "SK": { 280 | "S": "w#12345" 281 | }, 282 | "EntityType": { 283 | "S": "warehouseItem" 284 | }, 285 | "Quantity": { 286 | "S": "4" 287 | } 288 | }, 289 | { 290 | "PK": { 291 | "S": "p#99887" 292 | }, 293 | "SK": { 294 | "S": "w#12376" 295 | }, 296 | "EntityType": { 297 | "S": "warehouseItem" 298 | }, 299 | "Quantity": { 300 | "S": "4" 301 | } 302 | }, 303 | { 304 | "PK": { 305 | "S": "o#12345" 306 | }, 307 | "SK": { 308 | "S": "p#12345" 309 | }, 310 | "EntityType": { 311 | "S": "orderItem" 312 | }, 313 | "GSI1-PK": { 314 | "S": "p#12345" 315 | }, 316 | "GSI1-SK": { 317 | "S": "2020-06-21T19:18:00" 318 | }, 319 | "Quantity": { 320 | "S": "2" 321 | }, 322 | "Price": { 323 | "S": "100" 324 | } 325 | }, 326 | { 327 | "PK": { 328 | "S": "o#12345" 329 | }, 330 | "SK": { 331 | "S": "p#99887" 332 | }, 333 | "EntityType": { 334 | "S": "orderItem" 335 | }, 336 | "GSI1-PK": { 337 | "S": "p#99887" 338 | }, 339 | "GSI1-SK": { 340 | "S": "2020-06-21T19:20:00" 341 | }, 342 | "Quantity": { 343 | "S": "5" 344 | }, 345 | "Price": { 346 | "S": "40" 347 | } 348 | }, 349 | { 350 | "PK": { 351 | "S": "o#12345" 352 | }, 353 | "SK": { 354 | "S": "c#12345" 355 | }, 356 | "EntityType": { 357 | "S": "order" 358 | }, 359 | "Date": { 360 | "S": "2020-06-21T19:10:00" 361 | } 362 | }, 363 | { 364 | "PK": { 365 | "S": "o#12345" 366 | }, 367 | "SK": { 368 | "S": "i#55443" 369 | }, 370 | "EntityType": { 371 | "S": "invoice" 372 | }, 373 | "Amount": { 374 | "S": "400" 375 | }, 376 | "Date": { 377 | "S": "2020-06-21T19:18:00" 378 | } 379 | }, 380 | { 381 | "PK": { 382 | "S": "o#12345" 383 | }, 384 | "SK": { 385 | "S": "sh#88899" 386 | }, 387 | "EntityType": { 388 | "S": "shipment" 389 | }, 390 | "WarehouseId": { 391 | "S": "w#12376" 392 | }, 393 | "Address": { 394 | "M": { 395 | "Country": { 396 | "S": "Sweden" 397 | }, 398 | "County": { 399 | "S": "Vastra Gotaland" 400 | }, 401 | "City": { 402 | "S": "Goteborg" 403 | }, 404 | "Street": { 405 | "S": "Slanbarsvagen" 406 | }, 407 | "Number": { 408 | "S": "34" 409 | }, 410 | "ZipCode": { 411 | "S": "41787" 412 | } 413 | } 414 | }, 415 | "Type": { 416 | "S": "Express" 417 | }, 418 | "Date": { 419 | "S": "2020-06-22T08:20:00" 420 | } 421 | }, 422 | { 423 | "PK": { 424 | "S": "o#12345" 425 | }, 426 | "SK": { 427 | "S": "sh#98765" 428 | }, 429 | "EntityType": { 430 | "S": "shipment" 431 | }, 432 | "WarehouseId": { 433 | "S": "w#12345" 434 | }, 435 | "Address": { 436 | "M": { 437 | "Country": { 438 | "S": "Sweden" 439 | }, 440 | "County": { 441 | "S": "Vastra Gotaland" 442 | }, 443 | "City": { 444 | "S": "Goteborg" 445 | }, 446 | "Street": { 447 | "S": "Slanbarsvagen" 448 | }, 449 | "Number": { 450 | "S": "34" 451 | }, 452 | "ZipCode": { 453 | "S": "41787" 454 | } 455 | } 456 | }, 457 | "Type": { 458 | "S": "Express" 459 | }, 460 | "Date": { 461 | "S": "2020-06-22T10:20:00" 462 | } 463 | } 464 | ], 465 | "DataAccess": { 466 | "MySql": {} 467 | } 468 | } 469 | ] 470 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_11.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 09:56 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "GSI1-PK", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "GSI1-SK", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Email", 38 | "AttributeType": "S" 39 | }, 40 | { 41 | "AttributeName": "Name", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Detail", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Price", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Address", 54 | "AttributeType": "M" 55 | }, 56 | { 57 | "AttributeName": "Quantity", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Type", 62 | "AttributeType": "S" 63 | }, 64 | { 65 | "AttributeName": "Amount", 66 | "AttributeType": "S" 67 | }, 68 | { 69 | "AttributeName": "Date", 70 | "AttributeType": "S" 71 | }, 72 | { 73 | "AttributeName": "WarehouseId", 74 | "AttributeType": "S" 75 | } 76 | ], 77 | "GlobalSecondaryIndexes": [ 78 | { 79 | "IndexName": "GSI1", 80 | "KeyAttributes": { 81 | "PartitionKey": { 82 | "AttributeName": "GSI1-PK", 83 | "AttributeType": "S" 84 | }, 85 | "SortKey": { 86 | "AttributeName": "GSI1-SK", 87 | "AttributeType": "S" 88 | } 89 | }, 90 | "Projection": { 91 | "ProjectionType": "ALL" 92 | } 93 | } 94 | ], 95 | "TableData": [ 96 | { 97 | "PK": { 98 | "S": "c#12345" 99 | }, 100 | "SK": { 101 | "S": "c#12345" 102 | }, 103 | "EntityType": { 104 | "S": "customer" 105 | }, 106 | "Email": { 107 | "S": "samaneh@example.com" 108 | }, 109 | "Name": { 110 | "S": "Samaneh" 111 | } 112 | }, 113 | { 114 | "PK": { 115 | "S": "c#23456" 116 | }, 117 | "SK": { 118 | "S": "c#23456" 119 | }, 120 | "EntityType": { 121 | "S": "customer" 122 | }, 123 | "Email": { 124 | "S": "kathleen@example.com" 125 | }, 126 | "Name": { 127 | "S": "Kathleen" 128 | } 129 | }, 130 | { 131 | "PK": { 132 | "S": "c#54321" 133 | }, 134 | "SK": { 135 | "S": "c#54321" 136 | }, 137 | "EntityType": { 138 | "S": "customer" 139 | }, 140 | "Email": { 141 | "S": "henrik@example.com" 142 | }, 143 | "Name": { 144 | "S": "Henrik" 145 | } 146 | }, 147 | { 148 | "PK": { 149 | "S": "p#12345" 150 | }, 151 | "SK": { 152 | "S": "p#12345" 153 | }, 154 | "EntityType": { 155 | "S": "product" 156 | }, 157 | "Detail": { 158 | "M": { 159 | "Name": { 160 | "S": "Options Open" 161 | }, 162 | "Description": { 163 | "S": "The latest album" 164 | } 165 | } 166 | }, 167 | "Price": { 168 | "S": "100" 169 | } 170 | }, 171 | { 172 | "PK": { 173 | "S": "p#99887" 174 | }, 175 | "SK": { 176 | "S": "p#99887" 177 | }, 178 | "EntityType": { 179 | "S": "product" 180 | }, 181 | "Detail": { 182 | "M": { 183 | "Name": { 184 | "S": "The Book" 185 | }, 186 | "Description": { 187 | "S": "The best book ever" 188 | } 189 | } 190 | }, 191 | "Price": { 192 | "S": "40" 193 | } 194 | }, 195 | { 196 | "PK": { 197 | "S": "w#12345" 198 | }, 199 | "SK": { 200 | "S": "w#12345" 201 | }, 202 | "EntityType": { 203 | "S": "warehouse" 204 | }, 205 | "Address": { 206 | "M": { 207 | "Country": { 208 | "S": "Sweden" 209 | }, 210 | "County": { 211 | "S": "Vastra Gotaland" 212 | }, 213 | "City": { 214 | "S": "Goteborg" 215 | }, 216 | "Street": { 217 | "S": "MainStreet" 218 | }, 219 | "Number": { 220 | "S": "20" 221 | }, 222 | "ZipCode": { 223 | "S": "41111" 224 | } 225 | } 226 | } 227 | }, 228 | { 229 | "PK": { 230 | "S": "w#12376" 231 | }, 232 | "SK": { 233 | "S": "w#12376" 234 | }, 235 | "EntityType": { 236 | "S": "warehouse" 237 | }, 238 | "Address": { 239 | "M": { 240 | "Country": { 241 | "S": "Sweden" 242 | }, 243 | "County": { 244 | "S": "Vastra Gotaland" 245 | }, 246 | "City": { 247 | "S": "Boras" 248 | }, 249 | "Street": { 250 | "S": "RiverStreet" 251 | }, 252 | "Number": { 253 | "S": "20" 254 | }, 255 | "ZipCode": { 256 | "S": "11111" 257 | } 258 | } 259 | } 260 | }, 261 | { 262 | "PK": { 263 | "S": "p#12345" 264 | }, 265 | "SK": { 266 | "S": "w#12345" 267 | }, 268 | "EntityType": { 269 | "S": "warehouseItem" 270 | }, 271 | "Quantity": { 272 | "S": "50" 273 | } 274 | }, 275 | { 276 | "PK": { 277 | "S": "p#99887" 278 | }, 279 | "SK": { 280 | "S": "w#12345" 281 | }, 282 | "EntityType": { 283 | "S": "warehouseItem" 284 | }, 285 | "Quantity": { 286 | "S": "4" 287 | } 288 | }, 289 | { 290 | "PK": { 291 | "S": "p#99887" 292 | }, 293 | "SK": { 294 | "S": "w#12376" 295 | }, 296 | "EntityType": { 297 | "S": "warehouseItem" 298 | }, 299 | "Quantity": { 300 | "S": "4" 301 | } 302 | }, 303 | { 304 | "PK": { 305 | "S": "o#12345" 306 | }, 307 | "SK": { 308 | "S": "p#12345" 309 | }, 310 | "EntityType": { 311 | "S": "orderItem" 312 | }, 313 | "GSI1-PK": { 314 | "S": "p#12345" 315 | }, 316 | "GSI1-SK": { 317 | "S": "2020-06-21T19:18:00" 318 | }, 319 | "Quantity": { 320 | "S": "2" 321 | }, 322 | "Price": { 323 | "S": "100" 324 | } 325 | }, 326 | { 327 | "PK": { 328 | "S": "o#12345" 329 | }, 330 | "SK": { 331 | "S": "p#99887" 332 | }, 333 | "EntityType": { 334 | "S": "orderItem" 335 | }, 336 | "GSI1-PK": { 337 | "S": "p#99887" 338 | }, 339 | "GSI1-SK": { 340 | "S": "2020-06-21T19:20:00" 341 | }, 342 | "Quantity": { 343 | "S": "5" 344 | }, 345 | "Price": { 346 | "S": "40" 347 | } 348 | }, 349 | { 350 | "PK": { 351 | "S": "o#12345" 352 | }, 353 | "SK": { 354 | "S": "c#12345" 355 | }, 356 | "EntityType": { 357 | "S": "order" 358 | }, 359 | "Date": { 360 | "S": "2020-06-21T19:10:00" 361 | } 362 | }, 363 | { 364 | "PK": { 365 | "S": "o#12345" 366 | }, 367 | "SK": { 368 | "S": "i#55443" 369 | }, 370 | "EntityType": { 371 | "S": "invoice" 372 | }, 373 | "GSI1-PK": { 374 | "S": "i#55443" 375 | }, 376 | "GSI1-SK": { 377 | "S": "i#55443" 378 | }, 379 | "Amount": { 380 | "S": "400" 381 | }, 382 | "Date": { 383 | "S": "2020-06-21T19:18:00" 384 | }, 385 | "Detail": { 386 | "M": { 387 | "Payments": { 388 | "L": [ 389 | { 390 | "M": { 391 | "Type": { 392 | "S": "GiftCard" 393 | }, 394 | "Amount": { 395 | "N": "100" 396 | }, 397 | "Data": { 398 | "S": "GiftCard data here..." 399 | } 400 | } 401 | }, 402 | { 403 | "M": { 404 | "Type": { 405 | "S": "MasterCard" 406 | }, 407 | "Amount": { 408 | "N": "300" 409 | }, 410 | "Data": { 411 | "S": "Payment data here..." 412 | } 413 | } 414 | } 415 | ] 416 | } 417 | } 418 | } 419 | }, 420 | { 421 | "PK": { 422 | "S": "o#12345" 423 | }, 424 | "SK": { 425 | "S": "sh#88899" 426 | }, 427 | "EntityType": { 428 | "S": "shipment" 429 | }, 430 | "WarehouseId": { 431 | "S": "w#12376" 432 | }, 433 | "Address": { 434 | "M": { 435 | "Country": { 436 | "S": "Sweden" 437 | }, 438 | "County": { 439 | "S": "Vastra Gotaland" 440 | }, 441 | "City": { 442 | "S": "Goteborg" 443 | }, 444 | "Street": { 445 | "S": "Slanbarsvagen" 446 | }, 447 | "Number": { 448 | "S": "34" 449 | }, 450 | "ZipCode": { 451 | "S": "41787" 452 | } 453 | } 454 | }, 455 | "Type": { 456 | "S": "Express" 457 | }, 458 | "Date": { 459 | "S": "2020-06-22T08:20:00" 460 | } 461 | }, 462 | { 463 | "PK": { 464 | "S": "o#12345" 465 | }, 466 | "SK": { 467 | "S": "sh#98765" 468 | }, 469 | "EntityType": { 470 | "S": "shipment" 471 | }, 472 | "WarehouseId": { 473 | "S": "w#12345" 474 | }, 475 | "Address": { 476 | "M": { 477 | "Country": { 478 | "S": "Sweden" 479 | }, 480 | "County": { 481 | "S": "Vastra Gotaland" 482 | }, 483 | "City": { 484 | "S": "Goteborg" 485 | }, 486 | "Street": { 487 | "S": "Slanbarsvagen" 488 | }, 489 | "Number": { 490 | "S": "34" 491 | }, 492 | "ZipCode": { 493 | "S": "41787" 494 | } 495 | } 496 | }, 497 | "Type": { 498 | "S": "Express" 499 | }, 500 | "Date": { 501 | "S": "2020-06-22T10:20:00" 502 | } 503 | } 504 | ], 505 | "DataAccess": { 506 | "MySql": {} 507 | } 508 | } 509 | ] 510 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_12.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 09:56 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "GSI1-PK", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "GSI1-SK", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "GSI2-PK", 38 | "AttributeType": "S" 39 | }, 40 | { 41 | "AttributeName": "GSI2-SK", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Email", 46 | "AttributeType": "S" 47 | }, 48 | { 49 | "AttributeName": "Name", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Detail", 54 | "AttributeType": "M" 55 | }, 56 | { 57 | "AttributeName": "Price", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Address", 62 | "AttributeType": "M" 63 | }, 64 | { 65 | "AttributeName": "Quantity", 66 | "AttributeType": "S" 67 | }, 68 | { 69 | "AttributeName": "Type", 70 | "AttributeType": "S" 71 | }, 72 | { 73 | "AttributeName": "Amount", 74 | "AttributeType": "S" 75 | }, 76 | { 77 | "AttributeName": "Date", 78 | "AttributeType": "S" 79 | }, 80 | { 81 | "AttributeName": "WarehouseId", 82 | "AttributeType": "S" 83 | } 84 | ], 85 | "GlobalSecondaryIndexes": [ 86 | { 87 | "IndexName": "GSI1", 88 | "KeyAttributes": { 89 | "PartitionKey": { 90 | "AttributeName": "GSI1-PK", 91 | "AttributeType": "S" 92 | }, 93 | "SortKey": { 94 | "AttributeName": "GSI1-SK", 95 | "AttributeType": "S" 96 | } 97 | }, 98 | "Projection": { 99 | "ProjectionType": "ALL" 100 | } 101 | }, 102 | { 103 | "IndexName": "GSI2", 104 | "KeyAttributes": { 105 | "PartitionKey": { 106 | "AttributeName": "GSI2-PK", 107 | "AttributeType": "S" 108 | }, 109 | "SortKey": { 110 | "AttributeName": "GSI2-SK", 111 | "AttributeType": "S" 112 | } 113 | }, 114 | "Projection": { 115 | "ProjectionType": "ALL" 116 | } 117 | } 118 | ], 119 | "TableData": [ 120 | { 121 | "PK": { 122 | "S": "c#12345" 123 | }, 124 | "SK": { 125 | "S": "c#12345" 126 | }, 127 | "EntityType": { 128 | "S": "customer" 129 | }, 130 | "Email": { 131 | "S": "samaneh@example.com" 132 | }, 133 | "Name": { 134 | "S": "Samaneh" 135 | } 136 | }, 137 | { 138 | "PK": { 139 | "S": "c#23456" 140 | }, 141 | "SK": { 142 | "S": "c#23456" 143 | }, 144 | "EntityType": { 145 | "S": "customer" 146 | }, 147 | "Email": { 148 | "S": "kathleen@example.com" 149 | }, 150 | "Name": { 151 | "S": "Kathleen" 152 | } 153 | }, 154 | { 155 | "PK": { 156 | "S": "c#54321" 157 | }, 158 | "SK": { 159 | "S": "c#54321" 160 | }, 161 | "EntityType": { 162 | "S": "customer" 163 | }, 164 | "Email": { 165 | "S": "henrik@example.com" 166 | }, 167 | "Name": { 168 | "S": "Henrik" 169 | } 170 | }, 171 | { 172 | "PK": { 173 | "S": "p#12345" 174 | }, 175 | "SK": { 176 | "S": "p#12345" 177 | }, 178 | "EntityType": { 179 | "S": "product" 180 | }, 181 | "Detail": { 182 | "M": { 183 | "Name": { 184 | "S": "Options Open" 185 | }, 186 | "Description": { 187 | "S": "The latest album" 188 | } 189 | } 190 | }, 191 | "Price": { 192 | "S": "100" 193 | } 194 | }, 195 | { 196 | "PK": { 197 | "S": "p#99887" 198 | }, 199 | "SK": { 200 | "S": "p#99887" 201 | }, 202 | "EntityType": { 203 | "S": "product" 204 | }, 205 | "Detail": { 206 | "M": { 207 | "Name": { 208 | "S": "The Book" 209 | }, 210 | "Description": { 211 | "S": "The best book ever" 212 | } 213 | } 214 | }, 215 | "Price": { 216 | "S": "40" 217 | } 218 | }, 219 | { 220 | "PK": { 221 | "S": "w#12345" 222 | }, 223 | "SK": { 224 | "S": "w#12345" 225 | }, 226 | "EntityType": { 227 | "S": "warehouse" 228 | }, 229 | "Address": { 230 | "M": { 231 | "Country": { 232 | "S": "Sweden" 233 | }, 234 | "County": { 235 | "S": "Vastra Gotaland" 236 | }, 237 | "City": { 238 | "S": "Goteborg" 239 | }, 240 | "Street": { 241 | "S": "MainStreet" 242 | }, 243 | "Number": { 244 | "S": "20" 245 | }, 246 | "ZipCode": { 247 | "S": "41111" 248 | } 249 | } 250 | } 251 | }, 252 | { 253 | "PK": { 254 | "S": "w#12376" 255 | }, 256 | "SK": { 257 | "S": "w#12376" 258 | }, 259 | "EntityType": { 260 | "S": "warehouse" 261 | }, 262 | "Address": { 263 | "M": { 264 | "Country": { 265 | "S": "Sweden" 266 | }, 267 | "County": { 268 | "S": "Vastra Gotaland" 269 | }, 270 | "City": { 271 | "S": "Boras" 272 | }, 273 | "Street": { 274 | "S": "RiverStreet" 275 | }, 276 | "Number": { 277 | "S": "20" 278 | }, 279 | "ZipCode": { 280 | "S": "11111" 281 | } 282 | } 283 | } 284 | }, 285 | { 286 | "PK": { 287 | "S": "p#12345" 288 | }, 289 | "SK": { 290 | "S": "w#12345" 291 | }, 292 | "EntityType": { 293 | "S": "warehouseItem" 294 | }, 295 | "Quantity": { 296 | "S": "50" 297 | } 298 | }, 299 | { 300 | "PK": { 301 | "S": "p#99887" 302 | }, 303 | "SK": { 304 | "S": "w#12345" 305 | }, 306 | "EntityType": { 307 | "S": "warehouseItem" 308 | }, 309 | "Quantity": { 310 | "S": "4" 311 | } 312 | }, 313 | { 314 | "PK": { 315 | "S": "p#99887" 316 | }, 317 | "SK": { 318 | "S": "w#12376" 319 | }, 320 | "EntityType": { 321 | "S": "warehouseItem" 322 | }, 323 | "Quantity": { 324 | "S": "4" 325 | } 326 | }, 327 | { 328 | "PK": { 329 | "S": "o#12345" 330 | }, 331 | "SK": { 332 | "S": "p#12345" 333 | }, 334 | "EntityType": { 335 | "S": "orderItem" 336 | }, 337 | "GSI1-PK": { 338 | "S": "p#12345" 339 | }, 340 | "GSI1-SK": { 341 | "S": "2020-06-21T19:18:00" 342 | }, 343 | "Quantity": { 344 | "S": "2" 345 | }, 346 | "Price": { 347 | "S": "100" 348 | } 349 | }, 350 | { 351 | "PK": { 352 | "S": "o#12345" 353 | }, 354 | "SK": { 355 | "S": "p#99887" 356 | }, 357 | "EntityType": { 358 | "S": "orderItem" 359 | }, 360 | "GSI1-PK": { 361 | "S": "p#99887" 362 | }, 363 | "GSI1-SK": { 364 | "S": "2020-06-21T19:20:00" 365 | }, 366 | "Quantity": { 367 | "S": "5" 368 | }, 369 | "Price": { 370 | "S": "40" 371 | } 372 | }, 373 | { 374 | "PK": { 375 | "S": "o#12345" 376 | }, 377 | "SK": { 378 | "S": "c#12345" 379 | }, 380 | "EntityType": { 381 | "S": "order" 382 | }, 383 | "Date": { 384 | "S": "2020-06-21T19:10:00" 385 | } 386 | }, 387 | { 388 | "PK": { 389 | "S": "o#12345" 390 | }, 391 | "SK": { 392 | "S": "i#55443" 393 | }, 394 | "EntityType": { 395 | "S": "invoice" 396 | }, 397 | "GSI1-PK": { 398 | "S": "i#55443" 399 | }, 400 | "GSI1-SK": { 401 | "S": "i#55443" 402 | }, 403 | "Amount": { 404 | "S": "400" 405 | }, 406 | "Date": { 407 | "S": "2020-06-21T19:18:00" 408 | }, 409 | "Detail": { 410 | "M": { 411 | "Payments": { 412 | "L": [ 413 | { 414 | "M": { 415 | "Type": { 416 | "S": "GiftCard" 417 | }, 418 | "Amount": { 419 | "N": "100" 420 | }, 421 | "Data": { 422 | "S": "GiftCard data here..." 423 | } 424 | } 425 | }, 426 | { 427 | "M": { 428 | "Type": { 429 | "S": "MasterCard" 430 | }, 431 | "Amount": { 432 | "N": "300" 433 | }, 434 | "Data": { 435 | "S": "Payment data here..." 436 | } 437 | } 438 | } 439 | ] 440 | } 441 | } 442 | } 443 | }, 444 | { 445 | "PK": { 446 | "S": "o#12345" 447 | }, 448 | "SK": { 449 | "S": "sh#88899" 450 | }, 451 | "EntityType": { 452 | "S": "shipment" 453 | }, 454 | "GSI1-PK": { 455 | "S": "sh#88899" 456 | }, 457 | "GSI1-SK": { 458 | "S": "sh#88899" 459 | }, 460 | "GSI2-PK": { 461 | "S": "w#12376" 462 | }, 463 | "GSI2-SK": { 464 | "S": "sh#88899" 465 | }, 466 | "Address": { 467 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 468 | }, 469 | "Type": { 470 | "S": "Express" 471 | }, 472 | "Date": { 473 | "S": "2020-06-22T08:20:00" 474 | } 475 | }, 476 | { 477 | "PK": { 478 | "S": "o#12345" 479 | }, 480 | "SK": { 481 | "S": "sh#98765" 482 | }, 483 | "EntityType": { 484 | "S": "shipment" 485 | }, 486 | "GSI1-PK": { 487 | "S": "sh#98765" 488 | }, 489 | "GSI1-SK": { 490 | "S": "sh#98765" 491 | }, 492 | "GSI2-PK": { 493 | "S": "w#12345" 494 | }, 495 | "GSI2-SK": { 496 | "S": "sh#98765" 497 | }, 498 | "Address": { 499 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 500 | }, 501 | "Type": { 502 | "S": "Express" 503 | }, 504 | "Date": { 505 | "S": "2020-06-22T10:20:00" 506 | } 507 | }, 508 | { 509 | "PK": { 510 | "S": "o#12345" 511 | }, 512 | "SK": { 513 | "S": "shp#55555" 514 | }, 515 | "EntityType": { 516 | "S": "shipmentItem" 517 | }, 518 | "GSI1-PK": { 519 | "S": "sh#98765" 520 | }, 521 | "GSI1-SK": { 522 | "S": "p#12345" 523 | }, 524 | "Quantity": { 525 | "S": "2" 526 | } 527 | }, 528 | { 529 | "PK": { 530 | "S": "o#12345" 531 | }, 532 | "SK": { 533 | "S": "shp#12345" 534 | }, 535 | "EntityType": { 536 | "S": "shipmentItem" 537 | }, 538 | "GSI1-PK": { 539 | "S": "sh#98765" 540 | }, 541 | "GSI1-SK": { 542 | "S": "p#99887" 543 | }, 544 | "Quantity": { 545 | "S": "3" 546 | } 547 | }, 548 | { 549 | "PK": { 550 | "S": "o#12345" 551 | }, 552 | "SK": { 553 | "S": "shp#54321" 554 | }, 555 | "EntityType": { 556 | "S": "shipmentItem" 557 | }, 558 | "GSI1-PK": { 559 | "S": "sh#88899" 560 | }, 561 | "GSI1-SK": { 562 | "S": "p#99887" 563 | }, 564 | "Quantity": { 565 | "S": "2" 566 | } 567 | } 568 | ], 569 | "DataAccess": { 570 | "MySql": {} 571 | } 572 | } 573 | ] 574 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_13.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 09:56 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "GSI1-PK", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "GSI1-SK", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "GSI2-PK", 38 | "AttributeType": "S" 39 | }, 40 | { 41 | "AttributeName": "GSI2-SK", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Email", 46 | "AttributeType": "S" 47 | }, 48 | { 49 | "AttributeName": "Name", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Detail", 54 | "AttributeType": "M" 55 | }, 56 | { 57 | "AttributeName": "Price", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Address", 62 | "AttributeType": "M" 63 | }, 64 | { 65 | "AttributeName": "Quantity", 66 | "AttributeType": "S" 67 | }, 68 | { 69 | "AttributeName": "Type", 70 | "AttributeType": "S" 71 | }, 72 | { 73 | "AttributeName": "Amount", 74 | "AttributeType": "S" 75 | }, 76 | { 77 | "AttributeName": "Date", 78 | "AttributeType": "S" 79 | } 80 | ], 81 | "GlobalSecondaryIndexes": [ 82 | { 83 | "IndexName": "GSI1", 84 | "KeyAttributes": { 85 | "PartitionKey": { 86 | "AttributeName": "GSI1-PK", 87 | "AttributeType": "S" 88 | }, 89 | "SortKey": { 90 | "AttributeName": "GSI1-SK", 91 | "AttributeType": "S" 92 | } 93 | }, 94 | "Projection": { 95 | "ProjectionType": "ALL" 96 | } 97 | }, 98 | { 99 | "IndexName": "GSI2", 100 | "KeyAttributes": { 101 | "PartitionKey": { 102 | "AttributeName": "GSI2-PK", 103 | "AttributeType": "S" 104 | }, 105 | "SortKey": { 106 | "AttributeName": "GSI2-SK", 107 | "AttributeType": "S" 108 | } 109 | }, 110 | "Projection": { 111 | "ProjectionType": "ALL" 112 | } 113 | } 114 | ], 115 | "TableData": [ 116 | { 117 | "PK": { 118 | "S": "c#12345" 119 | }, 120 | "SK": { 121 | "S": "c#12345" 122 | }, 123 | "EntityType": { 124 | "S": "customer" 125 | }, 126 | "Email": { 127 | "S": "samaneh@example.com" 128 | }, 129 | "Name": { 130 | "S": "Samaneh" 131 | } 132 | }, 133 | { 134 | "PK": { 135 | "S": "c#23456" 136 | }, 137 | "SK": { 138 | "S": "c#23456" 139 | }, 140 | "EntityType": { 141 | "S": "customer" 142 | }, 143 | "Email": { 144 | "S": "kathleen@example.com" 145 | }, 146 | "Name": { 147 | "S": "Kathleen" 148 | } 149 | }, 150 | { 151 | "PK": { 152 | "S": "c#54321" 153 | }, 154 | "SK": { 155 | "S": "c#54321" 156 | }, 157 | "EntityType": { 158 | "S": "customer" 159 | }, 160 | "Email": { 161 | "S": "henrik@example.com" 162 | }, 163 | "Name": { 164 | "S": "Henrik" 165 | } 166 | }, 167 | { 168 | "PK": { 169 | "S": "p#12345" 170 | }, 171 | "SK": { 172 | "S": "p#12345" 173 | }, 174 | "EntityType": { 175 | "S": "product" 176 | }, 177 | "Detail": { 178 | "M": { 179 | "Name": { 180 | "S": "Options Open" 181 | }, 182 | "Description": { 183 | "S": "The latest album" 184 | } 185 | } 186 | }, 187 | "Price": { 188 | "S": "100" 189 | } 190 | }, 191 | { 192 | "PK": { 193 | "S": "p#99887" 194 | }, 195 | "SK": { 196 | "S": "p#99887" 197 | }, 198 | "EntityType": { 199 | "S": "product" 200 | }, 201 | "Detail": { 202 | "M": { 203 | "Name": { 204 | "S": "The Book" 205 | }, 206 | "Description": { 207 | "S": "The best book ever" 208 | } 209 | } 210 | }, 211 | "Price": { 212 | "S": "40" 213 | } 214 | }, 215 | { 216 | "PK": { 217 | "S": "w#12345" 218 | }, 219 | "SK": { 220 | "S": "w#12345" 221 | }, 222 | "EntityType": { 223 | "S": "warehouse" 224 | }, 225 | "Address": { 226 | "M": { 227 | "Country": { 228 | "S": "Sweden" 229 | }, 230 | "County": { 231 | "S": "Vastra Gotaland" 232 | }, 233 | "City": { 234 | "S": "Goteborg" 235 | }, 236 | "Street": { 237 | "S": "MainStreet" 238 | }, 239 | "Number": { 240 | "S": "20" 241 | }, 242 | "ZipCode": { 243 | "S": "41111" 244 | } 245 | } 246 | } 247 | }, 248 | { 249 | "PK": { 250 | "S": "w#12376" 251 | }, 252 | "SK": { 253 | "S": "w#12376" 254 | }, 255 | "EntityType": { 256 | "S": "warehouse" 257 | }, 258 | "Address": { 259 | "M": { 260 | "Country": { 261 | "S": "Sweden" 262 | }, 263 | "County": { 264 | "S": "Vastra Gotaland" 265 | }, 266 | "City": { 267 | "S": "Boras" 268 | }, 269 | "Street": { 270 | "S": "RiverStreet" 271 | }, 272 | "Number": { 273 | "S": "20" 274 | }, 275 | "ZipCode": { 276 | "S": "11111" 277 | } 278 | } 279 | } 280 | }, 281 | { 282 | "PK": { 283 | "S": "p#12345" 284 | }, 285 | "SK": { 286 | "S": "w#12345" 287 | }, 288 | "EntityType": { 289 | "S": "warehouseItem" 290 | }, 291 | "GSI2-PK": { 292 | "S": "w#12345" 293 | }, 294 | "GSI2-SK": { 295 | "S": "p#12345" 296 | }, 297 | "Quantity": { 298 | "S": "50" 299 | } 300 | }, 301 | { 302 | "PK": { 303 | "S": "p#99887" 304 | }, 305 | "SK": { 306 | "S": "w#12345" 307 | }, 308 | "EntityType": { 309 | "S": "warehouseItem" 310 | }, 311 | "GSI2-PK": { 312 | "S": "w#12345" 313 | }, 314 | "GSI2-SK": { 315 | "S": "p#99887" 316 | }, 317 | "Quantity": { 318 | "S": "4" 319 | } 320 | }, 321 | { 322 | "PK": { 323 | "S": "p#99887" 324 | }, 325 | "SK": { 326 | "S": "w#12376" 327 | }, 328 | "EntityType": { 329 | "S": "warehouseItem" 330 | }, 331 | "Quantity": { 332 | "S": "4" 333 | } 334 | }, 335 | { 336 | "PK": { 337 | "S": "o#12345" 338 | }, 339 | "SK": { 340 | "S": "p#12345" 341 | }, 342 | "EntityType": { 343 | "S": "orderItem" 344 | }, 345 | "GSI1-PK": { 346 | "S": "p#12345" 347 | }, 348 | "GSI1-SK": { 349 | "S": "2020-06-21T19:18:00" 350 | }, 351 | "GSI2-PK": { 352 | "S": "c#12345" 353 | }, 354 | "GSI2-SK": { 355 | "S": "p#2020-06-21T19:18:00" 356 | }, 357 | "Quantity": { 358 | "S": "2" 359 | }, 360 | "Price": { 361 | "S": "100" 362 | } 363 | }, 364 | { 365 | "PK": { 366 | "S": "o#12345" 367 | }, 368 | "SK": { 369 | "S": "p#99887" 370 | }, 371 | "EntityType": { 372 | "S": "orderItem" 373 | }, 374 | "GSI1-PK": { 375 | "S": "p#99887" 376 | }, 377 | "GSI1-SK": { 378 | "S": "2020-06-21T19:20:00" 379 | }, 380 | "GSI2-PK": { 381 | "S": "c#12345" 382 | }, 383 | "GSI2-SK": { 384 | "S": "p#2020-06-21T19:20:00" 385 | }, 386 | "Quantity": { 387 | "S": "5" 388 | }, 389 | "Price": { 390 | "S": "40" 391 | } 392 | }, 393 | { 394 | "PK": { 395 | "S": "o#12345" 396 | }, 397 | "SK": { 398 | "S": "c#12345" 399 | }, 400 | "EntityType": { 401 | "S": "order" 402 | }, 403 | "Date": { 404 | "S": "2020-06-21T19:10:00" 405 | } 406 | }, 407 | { 408 | "PK": { 409 | "S": "o#12345" 410 | }, 411 | "SK": { 412 | "S": "i#55443" 413 | }, 414 | "EntityType": { 415 | "S": "invoice" 416 | }, 417 | "GSI1-PK": { 418 | "S": "i#55443" 419 | }, 420 | "GSI1-SK": { 421 | "S": "i#55443" 422 | }, 423 | "GSI2-PK": { 424 | "S": "c#12345" 425 | }, 426 | "GSI2-SK": { 427 | "S": "i#2020-06-21T19:18:00" 428 | }, 429 | "Amount": { 430 | "S": "400" 431 | }, 432 | "Date": { 433 | "S": "2020-06-21T19:18:00" 434 | }, 435 | "Detail": { 436 | "M": { 437 | "Payments": { 438 | "L": [ 439 | { 440 | "M": { 441 | "Type": { 442 | "S": "GiftCard" 443 | }, 444 | "Amount": { 445 | "N": "100" 446 | }, 447 | "Data": { 448 | "S": "GiftCard data here..." 449 | } 450 | } 451 | }, 452 | { 453 | "M": { 454 | "Type": { 455 | "S": "MasterCard" 456 | }, 457 | "Amount": { 458 | "N": "300" 459 | }, 460 | "Data": { 461 | "S": "Payment data here..." 462 | } 463 | } 464 | } 465 | ] 466 | } 467 | } 468 | } 469 | }, 470 | { 471 | "PK": { 472 | "S": "o#12345" 473 | }, 474 | "SK": { 475 | "S": "sh#88899" 476 | }, 477 | "EntityType": { 478 | "S": "shipment" 479 | }, 480 | "GSI1-PK": { 481 | "S": "sh#88899" 482 | }, 483 | "GSI1-SK": { 484 | "S": "sh#88899" 485 | }, 486 | "GSI2-PK": { 487 | "S": "w#12376" 488 | }, 489 | "GSI2-SK": { 490 | "S": "sh#88899" 491 | }, 492 | "Address": { 493 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 494 | }, 495 | "Type": { 496 | "S": "Express" 497 | }, 498 | "Date": { 499 | "S": "2020-06-22T08:20:00" 500 | } 501 | }, 502 | { 503 | "PK": { 504 | "S": "o#12345" 505 | }, 506 | "SK": { 507 | "S": "sh#98765" 508 | }, 509 | "EntityType": { 510 | "S": "shipment" 511 | }, 512 | "GSI1-PK": { 513 | "S": "sh#98765" 514 | }, 515 | "GSI1-SK": { 516 | "S": "sh#98765" 517 | }, 518 | "GSI2-PK": { 519 | "S": "w#12345" 520 | }, 521 | "GSI2-SK": { 522 | "S": "sh#98765" 523 | }, 524 | "Address": { 525 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 526 | }, 527 | "Type": { 528 | "S": "Express" 529 | }, 530 | "Date": { 531 | "S": "2020-06-22T10:20:00" 532 | } 533 | }, 534 | { 535 | "PK": { 536 | "S": "o#12345" 537 | }, 538 | "SK": { 539 | "S": "shp#55555" 540 | }, 541 | "EntityType": { 542 | "S": "shipmentItem" 543 | }, 544 | "GSI1-PK": { 545 | "S": "sh#98765" 546 | }, 547 | "GSI1-SK": { 548 | "S": "p#12345" 549 | }, 550 | "Quantity": { 551 | "S": "2" 552 | } 553 | }, 554 | { 555 | "PK": { 556 | "S": "o#12345" 557 | }, 558 | "SK": { 559 | "S": "shp#12345" 560 | }, 561 | "EntityType": { 562 | "S": "shipmentItem" 563 | }, 564 | "GSI1-PK": { 565 | "S": "sh#98765" 566 | }, 567 | "GSI1-SK": { 568 | "S": "p#99887" 569 | }, 570 | "Quantity": { 571 | "S": "3" 572 | } 573 | }, 574 | { 575 | "PK": { 576 | "S": "o#12345" 577 | }, 578 | "SK": { 579 | "S": "shp#54321" 580 | }, 581 | "EntityType": { 582 | "S": "shipmentItem" 583 | }, 584 | "GSI1-PK": { 585 | "S": "sh#88899" 586 | }, 587 | "GSI1-SK": { 588 | "S": "p#99887" 589 | }, 590 | "Quantity": { 591 | "S": "2" 592 | } 593 | } 594 | ], 595 | "DataAccess": { 596 | "MySql": {} 597 | } 598 | } 599 | ] 600 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 04:28 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | } 36 | ], 37 | "TableData": [ 38 | { 39 | "PK": { 40 | "S": "c#12345" 41 | }, 42 | "SK": { 43 | "S": "c#12345" 44 | }, 45 | "EntityType": { 46 | "S": "customer" 47 | }, 48 | "Email": { 49 | "S": "samaneh@example.com" 50 | }, 51 | "Name": { 52 | "S": "Samaneh" 53 | } 54 | } 55 | ], 56 | "DataAccess": { 57 | "MySql": {} 58 | } 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:29 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | } 44 | ], 45 | "TableData": [ 46 | { 47 | "PK": { 48 | "S": "c#12345" 49 | }, 50 | "SK": { 51 | "S": "c#12345" 52 | }, 53 | "EntityType": { 54 | "S": "customer" 55 | }, 56 | "Email": { 57 | "S": "samaneh@example.com" 58 | }, 59 | "Name": { 60 | "S": "Samaneh" 61 | } 62 | }, 63 | { 64 | "PK": { 65 | "S": "p#12345" 66 | }, 67 | "SK": { 68 | "S": "p#12345" 69 | }, 70 | "EntityType": { 71 | "S": "product" 72 | }, 73 | "Detail": { 74 | "M": { 75 | "Name": { 76 | "S": "Options Open" 77 | }, 78 | "Description": { 79 | "S": "The latest album" 80 | } 81 | } 82 | }, 83 | "Price": { 84 | "S": "100" 85 | } 86 | } 87 | ], 88 | "DataAccess": { 89 | "MySql": {} 90 | } 91 | } 92 | ] 93 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:29 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | } 48 | ], 49 | "TableData": [ 50 | { 51 | "PK": { 52 | "S": "c#12345" 53 | }, 54 | "SK": { 55 | "S": "c#12345" 56 | }, 57 | "EntityType": { 58 | "S": "customer" 59 | }, 60 | "Email": { 61 | "S": "samaneh@example.com" 62 | }, 63 | "Name": { 64 | "S": "Samaneh" 65 | } 66 | }, 67 | { 68 | "PK": { 69 | "S": "p#12345" 70 | }, 71 | "SK": { 72 | "S": "p#12345" 73 | }, 74 | "EntityType": { 75 | "S": "product" 76 | }, 77 | "Detail": { 78 | "M": { 79 | "Name": { 80 | "S": "Options Open" 81 | }, 82 | "Description": { 83 | "S": "The latest album" 84 | } 85 | } 86 | }, 87 | "Price": { 88 | "S": "100" 89 | } 90 | }, 91 | { 92 | "PK": { 93 | "S": "w#12345" 94 | }, 95 | "SK": { 96 | "S": "w#12345" 97 | }, 98 | "EntityType": { 99 | "S": "warehouse" 100 | }, 101 | "Address": { 102 | "M": { 103 | "Country": { 104 | "S": "Sweden" 105 | }, 106 | "County": { 107 | "S": "Vastra Gotaland" 108 | }, 109 | "City": { 110 | "S": "Goteborg" 111 | }, 112 | "Street": { 113 | "S": "MainStreet" 114 | }, 115 | "Number": { 116 | "S": "20" 117 | }, 118 | "ZipCode": { 119 | "S": "41111" 120 | } 121 | } 122 | } 123 | } 124 | ], 125 | "DataAccess": { 126 | "MySql": {} 127 | } 128 | } 129 | ] 130 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:37 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Quantity", 50 | "AttributeType": "S" 51 | } 52 | ], 53 | "TableData": [ 54 | { 55 | "PK": { 56 | "S": "c#12345" 57 | }, 58 | "SK": { 59 | "S": "c#12345" 60 | }, 61 | "EntityType": { 62 | "S": "customer" 63 | }, 64 | "Email": { 65 | "S": "samaneh@example.com" 66 | }, 67 | "Name": { 68 | "S": "Samaneh" 69 | } 70 | }, 71 | { 72 | "PK": { 73 | "S": "p#12345" 74 | }, 75 | "SK": { 76 | "S": "p#12345" 77 | }, 78 | "EntityType": { 79 | "S": "product" 80 | }, 81 | "Detail": { 82 | "M": { 83 | "Name": { 84 | "S": "Options Open" 85 | }, 86 | "Description": { 87 | "S": "The latest album" 88 | } 89 | } 90 | }, 91 | "Price": { 92 | "S": "100" 93 | } 94 | }, 95 | { 96 | "PK": { 97 | "S": "w#12345" 98 | }, 99 | "SK": { 100 | "S": "w#12345" 101 | }, 102 | "EntityType": { 103 | "S": "warehouse" 104 | }, 105 | "Address": { 106 | "M": { 107 | "Country": { 108 | "S": "Sweden" 109 | }, 110 | "County": { 111 | "S": "Vastra Gotaland" 112 | }, 113 | "City": { 114 | "S": "Goteborg" 115 | }, 116 | "Street": { 117 | "S": "MainStreet" 118 | }, 119 | "Number": { 120 | "S": "20" 121 | }, 122 | "ZipCode": { 123 | "S": "41111" 124 | } 125 | } 126 | } 127 | }, 128 | { 129 | "PK": { 130 | "S": "p#12345" 131 | }, 132 | "SK": { 133 | "S": "w#12345" 134 | }, 135 | "EntityType": { 136 | "S": "warehouseItem" 137 | }, 138 | "Quantity": { 139 | "S": "50" 140 | } 141 | } 142 | ], 143 | "DataAccess": { 144 | "MySql": {} 145 | } 146 | } 147 | ] 148 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_6.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:37 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Quantity", 50 | "AttributeType": "S" 51 | } 52 | ], 53 | "TableData": [ 54 | { 55 | "PK": { 56 | "S": "c#12345" 57 | }, 58 | "SK": { 59 | "S": "c#12345" 60 | }, 61 | "EntityType": { 62 | "S": "customer" 63 | }, 64 | "Email": { 65 | "S": "samaneh@example.com" 66 | }, 67 | "Name": { 68 | "S": "Samaneh" 69 | } 70 | }, 71 | { 72 | "PK": { 73 | "S": "c#23456" 74 | }, 75 | "SK": { 76 | "S": "c#23456" 77 | }, 78 | "EntityType": { 79 | "S": "customer" 80 | }, 81 | "Email": { 82 | "S": "kathleen@example.com" 83 | }, 84 | "Name": { 85 | "S": "Kathleen" 86 | } 87 | }, 88 | { 89 | "PK": { 90 | "S": "c#54321" 91 | }, 92 | "SK": { 93 | "S": "c#54321" 94 | }, 95 | "EntityType": { 96 | "S": "customer" 97 | }, 98 | "Email": { 99 | "S": "henrik@example.com" 100 | }, 101 | "Name": { 102 | "S": "Henrik" 103 | } 104 | }, 105 | { 106 | "PK": { 107 | "S": "p#12345" 108 | }, 109 | "SK": { 110 | "S": "p#12345" 111 | }, 112 | "EntityType": { 113 | "S": "product" 114 | }, 115 | "Detail": { 116 | "M": { 117 | "Name": { 118 | "S": "Options Open" 119 | }, 120 | "Description": { 121 | "S": "The latest album" 122 | } 123 | } 124 | }, 125 | "Price": { 126 | "S": "100" 127 | } 128 | }, 129 | { 130 | "PK": { 131 | "S": "p#99887" 132 | }, 133 | "SK": { 134 | "S": "p#99887" 135 | }, 136 | "EntityType": { 137 | "S": "product" 138 | }, 139 | "Detail": { 140 | "M": { 141 | "Name": { 142 | "S": "The Book" 143 | }, 144 | "Description": { 145 | "S": "The best book ever" 146 | } 147 | } 148 | }, 149 | "Price": { 150 | "S": "40" 151 | } 152 | }, 153 | { 154 | "PK": { 155 | "S": "w#12345" 156 | }, 157 | "SK": { 158 | "S": "w#12345" 159 | }, 160 | "EntityType": { 161 | "S": "warehouse" 162 | }, 163 | "Address": { 164 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "MainStreet"},"Number": {"S": "20"},"ZipCode": {"S":"41111"}} 165 | } 166 | }, 167 | { 168 | "PK": { 169 | "S": "w#12376" 170 | }, 171 | "SK": { 172 | "S": "w#12376" 173 | }, 174 | "EntityType": { 175 | "S": "warehouse" 176 | }, 177 | "Address": { 178 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Boras"},"Street": {"S": "RiverStreet"},"Number": {"S": "20"},"ZipCode": {"S":"11111"}} 179 | } 180 | }, 181 | { 182 | "PK": { 183 | "S": "p#12345" 184 | }, 185 | "SK": { 186 | "S": "w#12345" 187 | }, 188 | "EntityType": { 189 | "S": "warehouseItem" 190 | }, 191 | "Quantity": { 192 | "S": "50" 193 | } 194 | }, 195 | { 196 | "PK": { 197 | "S": "p#99887" 198 | }, 199 | "SK": { 200 | "S": "w#12345" 201 | }, 202 | "EntityType": { 203 | "S": "warehouseItem" 204 | }, 205 | "Quantity": { 206 | "S": "4" 207 | } 208 | }, 209 | { 210 | "PK": { 211 | "S": "p#99887" 212 | }, 213 | "SK": { 214 | "S": "w#12376" 215 | }, 216 | "EntityType": { 217 | "S": "warehouseItem" 218 | }, 219 | "Quantity": { 220 | "S": "4" 221 | } 222 | } 223 | ], 224 | "DataAccess": { 225 | "MySql": {} 226 | } 227 | } 228 | ] 229 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:37 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Quantity", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Type", 54 | "AttributeType": "S" 55 | }, 56 | { 57 | "AttributeName": "Amount", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Date", 62 | "AttributeType": "S" 63 | } 64 | ], 65 | "TableData": [ 66 | { 67 | "PK": { 68 | "S": "c#12345" 69 | }, 70 | "SK": { 71 | "S": "c#12345" 72 | }, 73 | "EntityType": { 74 | "S": "customer" 75 | }, 76 | "Email": { 77 | "S": "samaneh@example.com" 78 | }, 79 | "Name": { 80 | "S": "Samaneh" 81 | } 82 | }, 83 | { 84 | "PK": { 85 | "S": "c#23456" 86 | }, 87 | "SK": { 88 | "S": "c#23456" 89 | }, 90 | "EntityType": { 91 | "S": "customer" 92 | }, 93 | "Email": { 94 | "S": "kathleen@example.com" 95 | }, 96 | "Name": { 97 | "S": "Kathleen" 98 | } 99 | }, 100 | { 101 | "PK": { 102 | "S": "c#54321" 103 | }, 104 | "SK": { 105 | "S": "c#54321" 106 | }, 107 | "EntityType": { 108 | "S": "customer" 109 | }, 110 | "Email": { 111 | "S": "henrik@example.com" 112 | }, 113 | "Name": { 114 | "S": "Henrik" 115 | } 116 | }, 117 | { 118 | "PK": { 119 | "S": "p#12345" 120 | }, 121 | "SK": { 122 | "S": "p#12345" 123 | }, 124 | "EntityType": { 125 | "S": "product" 126 | }, 127 | "Detail": { 128 | "M": { 129 | "Name": { 130 | "S": "Options Open" 131 | }, 132 | "Description": { 133 | "S": "The latest album" 134 | } 135 | } 136 | }, 137 | "Price": { 138 | "S": "100" 139 | } 140 | }, 141 | { 142 | "PK": { 143 | "S": "p#99887" 144 | }, 145 | "SK": { 146 | "S": "p#99887" 147 | }, 148 | "EntityType": { 149 | "S": "product" 150 | }, 151 | "Detail": { 152 | "M": { 153 | "Name": { 154 | "S": "The Book" 155 | }, 156 | "Description": { 157 | "S": "The best book ever" 158 | } 159 | } 160 | }, 161 | "Price": { 162 | "S": "40" 163 | } 164 | }, 165 | { 166 | "PK": { 167 | "S": "w#12345" 168 | }, 169 | "SK": { 170 | "S": "w#12345" 171 | }, 172 | "EntityType": { 173 | "S": "warehouse" 174 | }, 175 | "Address": { 176 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "MainStreet"},"Number": {"S": "20"},"ZipCode": {"S":"41111"}} 177 | } 178 | }, 179 | { 180 | "PK": { 181 | "S": "w#12376" 182 | }, 183 | "SK": { 184 | "S": "w#12376" 185 | }, 186 | "EntityType": { 187 | "S": "warehouse" 188 | }, 189 | "Address": { 190 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Boras"},"Street": {"S": "RiverStreet"},"Number": {"S": "20"},"ZipCode": {"S":"11111"}} 191 | } 192 | }, 193 | { 194 | "PK": { 195 | "S": "p#12345" 196 | }, 197 | "SK": { 198 | "S": "w#12345" 199 | }, 200 | "EntityType": { 201 | "S": "warehouseItem" 202 | }, 203 | "Quantity": { 204 | "S": "50" 205 | } 206 | }, 207 | { 208 | "PK": { 209 | "S": "p#99887" 210 | }, 211 | "SK": { 212 | "S": "w#12345" 213 | }, 214 | "EntityType": { 215 | "S": "warehouseItem" 216 | }, 217 | "Quantity": { 218 | "S": "4" 219 | } 220 | }, 221 | { 222 | "PK": { 223 | "S": "p#99887" 224 | }, 225 | "SK": { 226 | "S": "w#12376" 227 | }, 228 | "EntityType": { 229 | "S": "warehouseItem" 230 | }, 231 | "Quantity": { 232 | "S": "4" 233 | } 234 | }, 235 | { 236 | "PK": { 237 | "S": "o#12345" 238 | }, 239 | "SK": { 240 | "S": "p#12345" 241 | }, 242 | "EntityType": { 243 | "S": "orderItem" 244 | }, 245 | "Quantity": { 246 | "S": "2" 247 | }, 248 | "Price": { 249 | "S": "100" 250 | } 251 | }, 252 | { 253 | "PK": { 254 | "S": "o#12345" 255 | }, 256 | "SK": { 257 | "S": "p#99887" 258 | }, 259 | "EntityType": { 260 | "S": "orderItem" 261 | }, 262 | "Quantity": { 263 | "S": "5" 264 | }, 265 | "Price": { 266 | "S": "40" 267 | } 268 | }, 269 | { 270 | "PK": { 271 | "S": "o#12345" 272 | }, 273 | "SK": { 274 | "S": "c#12345" 275 | }, 276 | "EntityType": { 277 | "S": "order" 278 | }, 279 | "Date": { 280 | "S": "2020-06-21T19:10:00" 281 | } 282 | } 283 | ], 284 | "DataAccess": { 285 | "MySql": {} 286 | } 287 | } 288 | ] 289 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_8.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:37 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Quantity", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Type", 54 | "AttributeType": "S" 55 | }, 56 | { 57 | "AttributeName": "Amount", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Date", 62 | "AttributeType": "S" 63 | }, 64 | { 65 | "AttributeName": "ProductId", 66 | "AttributeType": "S" 67 | } 68 | ], 69 | "TableData": [ 70 | { 71 | "PK": { 72 | "S": "c#12345" 73 | }, 74 | "SK": { 75 | "S": "c#12345" 76 | }, 77 | "EntityType": { 78 | "S": "customer" 79 | }, 80 | "Email": { 81 | "S": "samaneh@example.com" 82 | }, 83 | "Name": { 84 | "S": "Samaneh" 85 | } 86 | }, 87 | { 88 | "PK": { 89 | "S": "c#23456" 90 | }, 91 | "SK": { 92 | "S": "c#23456" 93 | }, 94 | "EntityType": { 95 | "S": "customer" 96 | }, 97 | "Email": { 98 | "S": "kathleen@example.com" 99 | }, 100 | "Name": { 101 | "S": "Kathleen" 102 | } 103 | }, 104 | { 105 | "PK": { 106 | "S": "c#54321" 107 | }, 108 | "SK": { 109 | "S": "c#54321" 110 | }, 111 | "EntityType": { 112 | "S": "customer" 113 | }, 114 | "Email": { 115 | "S": "henrik@example.com" 116 | }, 117 | "Name": { 118 | "S": "Henrik" 119 | } 120 | }, 121 | { 122 | "PK": { 123 | "S": "p#12345" 124 | }, 125 | "SK": { 126 | "S": "p#12345" 127 | }, 128 | "EntityType": { 129 | "S": "product" 130 | }, 131 | "Detail": { 132 | "M": { 133 | "Name": { 134 | "S": "Options Open" 135 | }, 136 | "Description": { 137 | "S": "The latest album" 138 | } 139 | } 140 | }, 141 | "Price": { 142 | "S": "100" 143 | } 144 | }, 145 | { 146 | "PK": { 147 | "S": "p#99887" 148 | }, 149 | "SK": { 150 | "S": "p#99887" 151 | }, 152 | "EntityType": { 153 | "S": "product" 154 | }, 155 | "Detail": { 156 | "M": { 157 | "Name": { 158 | "S": "The Book" 159 | }, 160 | "Description": { 161 | "S": "The best book ever" 162 | } 163 | } 164 | }, 165 | "Price": { 166 | "S": "40" 167 | } 168 | }, 169 | { 170 | "PK": { 171 | "S": "w#12345" 172 | }, 173 | "SK": { 174 | "S": "w#12345" 175 | }, 176 | "EntityType": { 177 | "S": "warehouse" 178 | }, 179 | "Address": { 180 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "MainStreet"},"Number": {"S": "20"},"ZipCode": {"S":"41111"}} 181 | } 182 | }, 183 | { 184 | "PK": { 185 | "S": "w#12376" 186 | }, 187 | "SK": { 188 | "S": "w#12376" 189 | }, 190 | "EntityType": { 191 | "S": "warehouse" 192 | }, 193 | "Address": { 194 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Boras"},"Street": {"S": "RiverStreet"},"Number": {"S": "20"},"ZipCode": {"S":"11111"}} 195 | } 196 | }, 197 | { 198 | "PK": { 199 | "S": "p#12345" 200 | }, 201 | "SK": { 202 | "S": "w#12345" 203 | }, 204 | "EntityType": { 205 | "S": "warehouseItem" 206 | }, 207 | "Quantity": { 208 | "S": "50" 209 | } 210 | }, 211 | { 212 | "PK": { 213 | "S": "p#99887" 214 | }, 215 | "SK": { 216 | "S": "w#12345" 217 | }, 218 | "EntityType": { 219 | "S": "warehouseItem" 220 | }, 221 | "Quantity": { 222 | "S": "4" 223 | } 224 | }, 225 | { 226 | "PK": { 227 | "S": "p#99887" 228 | }, 229 | "SK": { 230 | "S": "w#12376" 231 | }, 232 | "EntityType": { 233 | "S": "warehouseItem" 234 | }, 235 | "Quantity": { 236 | "S": "4" 237 | } 238 | }, 239 | { 240 | "PK": { 241 | "S": "o#12345" 242 | }, 243 | "SK": { 244 | "S": "p#12345" 245 | }, 246 | "EntityType": { 247 | "S": "orderItem" 248 | }, 249 | "Quantity": { 250 | "S": "2" 251 | }, 252 | "Price": { 253 | "S": "100" 254 | } 255 | }, 256 | { 257 | "PK": { 258 | "S": "o#12345" 259 | }, 260 | "SK": { 261 | "S": "p#99887" 262 | }, 263 | "EntityType": { 264 | "S": "orderItem" 265 | }, 266 | "Quantity": { 267 | "S": "5" 268 | }, 269 | "Price": { 270 | "S": "40" 271 | } 272 | }, 273 | { 274 | "PK": { 275 | "S": "o#12345" 276 | }, 277 | "SK": { 278 | "S": "c#12345" 279 | }, 280 | "EntityType": { 281 | "S": "order" 282 | }, 283 | "Date": { 284 | "S": "2020-06-21T19:10:00" 285 | } 286 | }, 287 | { 288 | "PK": { 289 | "S": "o#12345" 290 | }, 291 | "SK": { 292 | "S": "i#55443" 293 | }, 294 | "EntityType": { 295 | "S": "invoice" 296 | }, 297 | "Amount": { 298 | "S": "400" 299 | }, 300 | "Date": { 301 | "S": "2020-06-21T19:18:00" 302 | } 303 | } 304 | ], 305 | "DataAccess": { 306 | "MySql": {} 307 | } 308 | } 309 | ] 310 | } -------------------------------------------------------------------------------- /examples/an-online-shop/json/AnOnlineShop_9.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "AnOnlineShop", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Jun 24, 2020, 04:20 PM", 6 | "DateLastModified": "Jun 24, 2020, 05:37 PM", 7 | "Description": "This data model represents an Amazon DynamoDB schema for an online shop.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "OnlineShop", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "PK", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "SK", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "EntityType", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Email", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "Name", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "Detail", 38 | "AttributeType": "M" 39 | }, 40 | { 41 | "AttributeName": "Price", 42 | "AttributeType": "S" 43 | }, 44 | { 45 | "AttributeName": "Address", 46 | "AttributeType": "M" 47 | }, 48 | { 49 | "AttributeName": "Quantity", 50 | "AttributeType": "S" 51 | }, 52 | { 53 | "AttributeName": "Type", 54 | "AttributeType": "S" 55 | }, 56 | { 57 | "AttributeName": "Amount", 58 | "AttributeType": "S" 59 | }, 60 | { 61 | "AttributeName": "Date", 62 | "AttributeType": "S" 63 | }, 64 | { 65 | "AttributeName": "WarehouseId", 66 | "AttributeType": "S" 67 | } 68 | ], 69 | "TableData": [ 70 | { 71 | "PK": { 72 | "S": "c#12345" 73 | }, 74 | "SK": { 75 | "S": "c#12345" 76 | }, 77 | "EntityType": { 78 | "S": "customer" 79 | }, 80 | "Email": { 81 | "S": "samaneh@example.com" 82 | }, 83 | "Name": { 84 | "S": "Samaneh" 85 | } 86 | }, 87 | { 88 | "PK": { 89 | "S": "c#23456" 90 | }, 91 | "SK": { 92 | "S": "c#23456" 93 | }, 94 | "EntityType": { 95 | "S": "customer" 96 | }, 97 | "Email": { 98 | "S": "kathleen@example.com" 99 | }, 100 | "Name": { 101 | "S": "Kathleen" 102 | } 103 | }, 104 | { 105 | "PK": { 106 | "S": "c#54321" 107 | }, 108 | "SK": { 109 | "S": "c#54321" 110 | }, 111 | "EntityType": { 112 | "S": "customer" 113 | }, 114 | "Email": { 115 | "S": "henrik@example.com" 116 | }, 117 | "Name": { 118 | "S": "Henrik" 119 | } 120 | }, 121 | { 122 | "PK": { 123 | "S": "p#12345" 124 | }, 125 | "SK": { 126 | "S": "p#12345" 127 | }, 128 | "EntityType": { 129 | "S": "product" 130 | }, 131 | "Detail": { 132 | "M": { 133 | "Name": { 134 | "S": "Options Open" 135 | }, 136 | "Description": { 137 | "S": "The latest album" 138 | } 139 | } 140 | }, 141 | "Price": { 142 | "S": "100" 143 | } 144 | }, 145 | { 146 | "PK": { 147 | "S": "p#99887" 148 | }, 149 | "SK": { 150 | "S": "p#99887" 151 | }, 152 | "EntityType": { 153 | "S": "product" 154 | }, 155 | "Detail": { 156 | "M": { 157 | "Name": { 158 | "S": "The Book" 159 | }, 160 | "Description": { 161 | "S": "The best book ever" 162 | } 163 | } 164 | }, 165 | "Price": { 166 | "S": "40" 167 | } 168 | }, 169 | { 170 | "PK": { 171 | "S": "w#12345" 172 | }, 173 | "SK": { 174 | "S": "w#12345" 175 | }, 176 | "EntityType": { 177 | "S": "warehouse" 178 | }, 179 | "Address": { 180 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "MainStreet"},"Number": {"S": "20"},"ZipCode": {"S":"41111"}} 181 | } 182 | }, 183 | { 184 | "PK": { 185 | "S": "w#12376" 186 | }, 187 | "SK": { 188 | "S": "w#12376" 189 | }, 190 | "EntityType": { 191 | "S": "warehouse" 192 | }, 193 | "Address": { 194 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Boras"},"Street": {"S": "RiverStreet"},"Number": {"S": "20"},"ZipCode": {"S":"11111"}} 195 | } 196 | }, 197 | { 198 | "PK": { 199 | "S": "p#12345" 200 | }, 201 | "SK": { 202 | "S": "w#12345" 203 | }, 204 | "EntityType": { 205 | "S": "warehouseItem" 206 | }, 207 | "Quantity": { 208 | "S": "50" 209 | } 210 | }, 211 | { 212 | "PK": { 213 | "S": "p#99887" 214 | }, 215 | "SK": { 216 | "S": "w#12345" 217 | }, 218 | "EntityType": { 219 | "S": "warehouseItem" 220 | }, 221 | "Quantity": { 222 | "S": "4" 223 | } 224 | }, 225 | { 226 | "PK": { 227 | "S": "p#99887" 228 | }, 229 | "SK": { 230 | "S": "w#12376" 231 | }, 232 | "EntityType": { 233 | "S": "warehouseItem" 234 | }, 235 | "Quantity": { 236 | "S": "4" 237 | } 238 | }, 239 | { 240 | "PK": { 241 | "S": "o#12345" 242 | }, 243 | "SK": { 244 | "S": "p#12345" 245 | }, 246 | "EntityType": { 247 | "S": "orderItem" 248 | }, 249 | "Quantity": { 250 | "S": "2" 251 | }, 252 | "Price": { 253 | "S": "100" 254 | } 255 | }, 256 | { 257 | "PK": { 258 | "S": "o#12345" 259 | }, 260 | "SK": { 261 | "S": "p#99887" 262 | }, 263 | "EntityType": { 264 | "S": "orderItem" 265 | }, 266 | "Quantity": { 267 | "S": "5" 268 | }, 269 | "Price": { 270 | "S": "40" 271 | } 272 | }, 273 | { 274 | "PK": { 275 | "S": "o#12345" 276 | }, 277 | "SK": { 278 | "S": "c#12345" 279 | }, 280 | "EntityType": { 281 | "S": "order" 282 | }, 283 | "Date": { 284 | "S": "2020-06-21T19:10:00" 285 | } 286 | }, 287 | { 288 | "PK": { 289 | "S": "o#12345" 290 | }, 291 | "SK": { 292 | "S": "i#55443" 293 | }, 294 | "EntityType": { 295 | "S": "invoice" 296 | }, 297 | "Amount": { 298 | "S": "400" 299 | }, 300 | "Date": { 301 | "S": "2020-06-21T19:18:00" 302 | } 303 | }, 304 | { 305 | "PK": { 306 | "S": "o#12345" 307 | }, 308 | "SK": { 309 | "S": "sh#88899" 310 | }, 311 | "EntityType": { 312 | "S": "shipment" 313 | }, 314 | "WarehouseId": { 315 | "S": "w#12376" 316 | }, 317 | "Address": { 318 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 319 | }, 320 | "Type": { 321 | "S": "Express" 322 | }, 323 | "Date": { 324 | "S": "2020-06-22T08:20:00" 325 | } 326 | }, 327 | { 328 | "PK": { 329 | "S": "o#12345" 330 | }, 331 | "SK": { 332 | "S": "sh#98765" 333 | }, 334 | "EntityType": { 335 | "S": "shipment" 336 | }, 337 | "WarehouseId": { 338 | "S": "w#12345" 339 | }, 340 | "Address": { 341 | "M": {"Country": {"S": "Sweden"},"County": {"S": "Vastra Gotaland"},"City": {"S": "Goteborg"},"Street": {"S": "Slanbarsvagen"},"Number": {"S": "111"},"ZipCode": {"S":"98765"}} 342 | }, 343 | "Type": { 344 | "S": "Express" 345 | }, 346 | "Date": { 347 | "S": "2020-06-22T10:20:00" 348 | } 349 | } 350 | ], 351 | "DataAccess": { 352 | "MySql": {} 353 | } 354 | } 355 | ] 356 | } -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShopErd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShopErd.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_1.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_2.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_3.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_4.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_5.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_6.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_6table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_6table.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_7.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_8a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_8a.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_8a_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_8a_table.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_8b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_8b.png -------------------------------------------------------------------------------- /examples/an-online-shop/resources/AnOnlineShop_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/an-online-shop/resources/AnOnlineShop_9.png -------------------------------------------------------------------------------- /examples/device-state-log/README.md: -------------------------------------------------------------------------------- 1 | # Device State Log 2 | 3 | This example covers: 4 | - how to use composite sort key instead of filter expression 5 | - how global secondary index makes it possible to create a new item collection from the existing items in a table 6 | - how indexes are sparse by default 7 | 8 | 9 | [NoSQL Workbench for Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html) is a great tool for designing and visualizing data models for Amazon DynamoDB applications. There are several data models in `json` format for each step of this example that can be imported in NoSQL Workbench. 10 | 11 | A bit of context on what this example is about: 12 | 13 | - In a factory, there are many **devices** that are monitored by human **operators**. 14 | - When there is a problem or abnormal behavior of a device, a message will be sent to the monitoring system indicating that the device state has changed from normal to warning. 15 | - There are different warning levels depending on the severity and type of abnormal behavior of the device. 16 | - The message will be sent every five minutes until the device state is back to normal. 17 | - The system will assign an operator to check the device. 18 | - An operator may escalate the problem to his/her **supervisor**. 19 | 20 | ## Composite Sort Key 21 | 22 | In NoSQL Workbench, import [DeviceStateLog_1.json](json/DeviceStateLog_1.json) to create `DeviceStateLog` table with example data. 23 |
24 |
25 | *Table* 26 |
27 | Table 28 |
29 | 30 | 31 | Let's look into how to handle the first access pattern for this example: 32 | 33 | | Access Pattern |Table/GSI/LSI|Key Condition|Filter Expression | Sort | Example | 34 | | :--- | :--- | :--- | :--- |:---|:---| 35 | | Get all logs for a specific device state showing the most recent logs first |Table|DeviceID=deviceId | State=state | Descending | DeviceID="d#12345", State="WARNING1" | 36 | 37 | Import [DeviceStateLog_2.json](json/DeviceStateLog_2.json) where `Detail` attribute was added to the table. 38 | 39 | The following AWS CLI example queries the `DeviceStateLog` table to retrieve all the logs that have `WARNING1` state for a device with `DeviceID = "d#12345"` and the most recent logs shown first. The statement `no-scan-index-forward` changes the default sort order from ascending to descending. 40 | 41 | ``` 42 | aws dynamodb query \ 43 | --table-name DeviceStateLog \ 44 | --key-condition-expression "#dID = :dID" \ 45 | --no-scan-index-forward \ 46 | --filter-expression "#s = :s" \ 47 | --expression-attribute-names '{"#dID":"DeviceID","#s":"State"}' \ 48 | --expression-attribute-values '{":dID":{"S":"d#12345"},":s":{"S":"WARNING1"}}' \ 49 | --return-consumed-capacity TOTAL 50 | ``` 51 | After running the query, apart from the actual returned items the output also contains this information: 52 | 53 | ``` 54 | "Count": 3, 55 | "ScannedCount": 4, 56 | "ConsumedCapacity": { 57 | "TableName": "DeviceStateLog", 58 | "CapacityUnits": 1.5 59 | } 60 | ``` 61 | 62 | [ScannedCount](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-response-ScannedCount) refers to all the logs that are found for this specific device **before** filter expression was applied. 63 | 64 | [Count](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-response-Count) refers to the final number of items that are returned **after** filter expression was applied. 65 | 66 | Note that [ConsumedCapacity](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-response-ConsumedCapacity) is calculated based on **ScannedCount**. 67 | 68 | For comparison, run the query below where the filter has been removed and observe the result: 69 | 70 | ``` 71 | aws dynamodb query \ 72 | --table-name DeviceStateLog \ 73 | --key-condition-expression "#dID = :dID" \ 74 | --no-scan-index-forward \ 75 | --expression-attribute-names '{"#dID":"DeviceID"}' \ 76 | --expression-attribute-values '{":dID":{"S":"d#12345"}}' \ 77 | --return-consumed-capacity TOTAL 78 | ``` 79 | ``` 80 | "Count": 4, 81 | "ScannedCount": 4, 82 | "ConsumedCapacity": { 83 | "TableName": "DeviceStateLog", 84 | "CapacityUnits": 1.5 85 | } 86 | ``` 87 | Let's see if there is another way to handle this access pattern. 88 | 89 | Import [DeviceStateLog_3.json](json/DeviceStateLog_3.json) where the sort key is changed to `State#Date` which is the composition of the attributes **State + \# + Date**. In this example, \# is used as a delimiter. 90 |
91 |
92 | *Table* 93 |
94 | Table 95 |
96 | 97 | | Access Pattern |Table/GSI/LSI|Key Condition|Filter Expression | Sort | Example | 98 | | :--- | :--- | :--- | :--- |:---|:---| 99 | | Get all logs for a specific device state showing the most recent logs first |Table|DeviceID=deviceId and State#Date **begins_with** "**state1#**"| - | Descending | DeviceID="d#12345" and State#Date begins_with "WARNING1#" | 100 | 101 | In the following AWS CLI example, [begins_with()](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) operator is used to retrieve only the logs that have the `WARNING1` state for the desired device. 102 | 103 | ``` 104 | aws dynamodb query \ 105 | --table-name DeviceStateLog \ 106 | --no-scan-index-forward \ 107 | --key-condition-expression "#dID = :dID AND begins_with(#s, :sd)" \ 108 | --expression-attribute-names '{"#dID":"DeviceID","#s":"State#Date"}' \ 109 | --expression-attribute-values '{":dID":{"S":"d#12345"},":sd":{"S":"WARNING1#"}}' \ 110 | --return-consumed-capacity TOTAL 111 | ``` 112 | 113 | Notice that `Count` and `ScannedCount` has the same value and that `ConsumedCapacity` has decreased as well. 114 | 115 | ``` 116 | "Count": 3, 117 | "ScannedCount": 3, 118 | "ConsumedCapacity": { 119 | "TableName": "DeviceStateLog", 120 | "CapacityUnits": 0.5 121 | } 122 | ``` 123 | 124 | Filter expression can be a good way to exclude items that are queried if the ratio of excluded items is low or the query is performed infrequently. For cases where many items are retrieved from a table and the majority of the items are filtered out, there could be a more efficient way to design the table. 125 | 126 | ## Create a New Item Collection with Global Secondary Index 127 | 128 | In NoSQL Workbench, import [DeviceStateLog_4.json](json/DeviceStateLog_4.json) where `Operator` attribute was added to the `DeviceStateLog` table with example data. 129 |
130 |
131 | *Table* 132 |
133 | Table
134 |
135 | The next access pattern is:
136 | **Get all device logs for a given operator between two dates**
137 |
138 | Item collection refers to item(s) that have the same partition key. So far, this table contains item collections for devices. In order to handle this new access pattern, create a new item collection where `Operator` is the partition key and `Date` is the sort key in a global secondary index (GSI). [Between](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html#Query.KeyConditionExpressions) operator retrieves only the logs that are in the desired date range. Import [DeviceStateLog_5.json](json/DeviceStateLog_5.json). 139 |
140 |
141 | *GSI1* 142 |
143 | GSI1 144 |
145 | | Access Pattern |Table/GSI/LSI|Key Condition|Filter Expression | Sort | Example | 146 | | :--- | :--- | :--- | :--- |:---|:---| 147 | | Get all device logs for a given operator between two dates | GSI1 |Operator = operatorName and Date **between** date1 **and** date2 | - | Ascending | Operator="Liz" and Date between "2020-04-20" and "2020-04-25" | 148 | 149 | Here is an AWS CLI example for this access pattern: 150 | 151 | ``` 152 | aws dynamodb query \ 153 | --table-name DeviceStateLog \ 154 | --index-name GSI1 \ 155 | --key-condition-expression "#op = :op AND #d between :d1 AND :d2" \ 156 | --expression-attribute-names '{"#op": "Operator" , "#d": "Date"}' \ 157 | --expression-attribute-values '{":op": {"S":"Liz"} , ":d1": {"S":"2020-04-20"}, ":d2":{"S":"2020-04-25"}}' \ 158 | --return-consumed-capacity TOTAL 159 | ``` 160 | 161 | ## Sparse Index 162 | 163 | Global secondary indexes are sparse by default, so only items in the base table that contain primary key attributes of the index will actually appear in the index. This is another way of excluding items that are not relevant for the access pattern being modeled. 164 | 165 | The last access patterns relates to:
166 | **Get all escalated device logs for a given supervisor** 167 | 168 | Import [DeviceStateLog_6.json](json/DeviceStateLog_6.json) where `EscalatedTo` attribute was added to the `DeviceStateLog` table with example data. As mentioned earlier, not all of the logs gets escalated to a supervisor. 169 |
170 |
171 | *Table* 172 |
173 | Table 174 |
175 |
176 | Import [DeviceStateLog_7.json](json/DeviceStateLog_7.json) to create a new global secondary index (GSI) where `EscalatedTo` is the partition key and `State#Date` is the sort key. Notice that only items that have both `EscalatedTo` and `State#Date` attributes appear in the index. 177 |
178 |
179 | *GSI2* 180 |
181 | GSI2 182 |
183 |
184 | | Access Pattern |Table/GSI/LSI|Key Condition|Filter Expression | Sort | Example | 185 | | :--- | :--- | :--- | :--- |:---|:---| 186 | | Get all escalated logs for a given supervisor | GSI2 |EscalatedTo=supervisorName | - | Ascending | EscalatedTo="Sara" | 187 | | Get all escalated logs with a specific device state for a given supervisor | GSI2 |EscalatedTo = supervisorName and State#Date **begins_with** "**state1#**"| - | Ascending | EscalatedTo="Sara" and State#Date **begins_with** "**WARNING4#**"| 188 | | Get all escalated logs with a specific device state for a given supervisor for a specific date | GSI2 |EscalatedTo = supervisorName and State#Date **begins_with** "**state1#date1**"| - | Ascending | EscalatedTo="Sara" and State#Date **begins_with** "**WARNING4#2020-04-27**" | 189 |
190 | Here is an AWS CLI example for these access patterns: 191 | 192 | ``` 193 | aws dynamodb query \ 194 | --table-name DeviceStateLog \ 195 | --index-name GSI2 \ 196 | --key-condition-expression "#su = :su" \ 197 | --expression-attribute-names '{"#su":"EscalatedTo"}' \ 198 | --expression-attribute-values '{":su":{"S":"Sara"}}' \ 199 | --return-consumed-capacity TOTAL 200 | ``` 201 | 202 | ``` 203 | aws dynamodb query \ 204 | --table-name DeviceStateLog \ 205 | --index-name GSI2 \ 206 | --key-condition-expression "#su = :su AND begins_with(#s, :sd)" \ 207 | --expression-attribute-names '{"#su":"EscalatedTo","#s":"State#Date"}' \ 208 | --expression-attribute-values '{":su":{"S":"Sara"},":sd":{"S":"WARNING4#"}}' \ 209 | --return-consumed-capacity TOTAL 210 | ``` 211 | 212 | ``` 213 | aws dynamodb query \ 214 | --table-name DeviceStateLog \ 215 | --index-name GSI2 \ 216 | --key-condition-expression "#su = :su AND begins_with(#s, :sd)" \ 217 | --expression-attribute-names '{"#su":"EscalatedTo","#s":"State#Date"}' \ 218 | --expression-attribute-values '{":su":{"S":"Sara"},":sd":{"S":"WARNING4#2020-04-27"}}' \ 219 | --return-consumed-capacity TOTAL 220 | ``` 221 | 222 | ## Final Words 223 | 224 | Congratulations! You made it to the end. 225 |
226 | Please keep in mind that the intention of this example is not to design a complete realistic device state management but rather show a few NoSQL design patterns. Always make sure to start defining your access patterns first and then build your model. 227 | -------------------------------------------------------------------------------- /examples/device-state-log/aws-cli-commands/aws-cli-dynamodb-commands.txt: -------------------------------------------------------------------------------- 1 | aws dynamodb query \ 2 | --table-name DeviceStateLog \ 3 | --key-condition-expression "#dID = :dID" \ 4 | --no-scan-index-forward \ 5 | --filter-expression "#s = :s" \ 6 | --expression-attribute-names '{"#dID":"DeviceID","#s":"State"}' \ 7 | --expression-attribute-values '{":dID":{"S":"d#12345"},":s":{"S":"WARNING1"}}' \ 8 | --return-consumed-capacity TOTAL 9 | 10 | aws dynamodb query \ 11 | --table-name DeviceStateLog \ 12 | --key-condition-expression "#dID = :dID" \ 13 | --no-scan-index-forward \ 14 | --expression-attribute-names '{"#dID":"DeviceID"}' \ 15 | --expression-attribute-values '{":dID":{"S":"d#12345"}}' \ 16 | --return-consumed-capacity TOTAL 17 | 18 | aws dynamodb query \ 19 | --table-name DeviceStateLog \ 20 | --no-scan-index-forward \ 21 | --key-condition-expression "#dID = :dID AND begins_with(#s, :sd)" \ 22 | --expression-attribute-names '{"#dID":"DeviceID","#s":"State#Date"}' \ 23 | --expression-attribute-values '{":dID":{"S":"d#12345"},":sd":{"S":"WARNING1#"}}' \ 24 | --return-consumed-capacity TOTAL 25 | 26 | aws dynamodb query \ 27 | --table-name DeviceStateLog \ 28 | --index-name GSI1 \ 29 | --key-condition-expression "#op = :op AND #d between :d1 AND :d2" \ 30 | --expression-attribute-names '{"#op": "Operator" , "#d": "Date"}' \ 31 | --expression-attribute-values '{":op": {"S":"Liz"} , ":d1": {"S":"2020-04-20"}, ":d2":{"S":"2020-04-25"}}' \ 32 | --return-consumed-capacity TOTAL 33 | 34 | aws dynamodb query \ 35 | --table-name DeviceStateLog \ 36 | --index-name GSI2 \ 37 | --key-condition-expression "#su = :su" \ 38 | --expression-attribute-names '{"#su":"EscalatedTo"}' \ 39 | --expression-attribute-values '{":su":{"S":"Sara"}}' \ 40 | --return-consumed-capacity TOTAL 41 | 42 | aws dynamodb query \ 43 | --table-name DeviceStateLog \ 44 | --index-name GSI2 \ 45 | --key-condition-expression "#su = :su AND begins_with(#s, :sd)" \ 46 | --expression-attribute-names '{"#su":"EscalatedTo","#s":"State#Date"}' \ 47 | --expression-attribute-values '{":su":{"S":"Sara"},":sd":{"S":"WARNING4#"}}' \ 48 | --return-consumed-capacity TOTAL 49 | 50 | aws dynamodb query \ 51 | --table-name DeviceStateLog \ 52 | --index-name GSI2 \ 53 | --key-condition-expression "#su = :su AND begins_with(#s, :sd)" \ 54 | --expression-attribute-names '{"#su":"EscalatedTo","#s":"State#Date"}' \ 55 | --expression-attribute-values '{":su":{"S":"Sara"},":sd":{"S":"WARNING4#2020-04-27"}}' \ 56 | --return-consumed-capacity TOTAL -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 10, 2020, 12:13 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "State", 26 | "AttributeType": "S" 27 | } 28 | ], 29 | "TableData": [ 30 | { 31 | "DeviceID": { 32 | "S": "d#12345" 33 | }, 34 | "Date": { 35 | "S": "2020-04-24T14:40:00" 36 | }, 37 | "State": { 38 | "S": "WARNING1" 39 | } 40 | }, 41 | { 42 | "DeviceID": { 43 | "S": "d#12345" 44 | }, 45 | "Date": { 46 | "S": "2020-04-24T14:45:00" 47 | }, 48 | "State": { 49 | "S": "WARNING1" 50 | } 51 | }, 52 | { 53 | "DeviceID": { 54 | "S": "d#12345" 55 | }, 56 | "Date": { 57 | "S": "2020-04-24T14:50:00" 58 | }, 59 | "State": { 60 | "S": "WARNING1" 61 | } 62 | }, 63 | { 64 | "DeviceID": { 65 | "S": "d#12345" 66 | }, 67 | "Date": { 68 | "S": "2020-04-24T14:55:00" 69 | }, 70 | "State": { 71 | "S": "NORMAL" 72 | } 73 | }, 74 | { 75 | "DeviceID": { 76 | "S": "d#54321" 77 | }, 78 | "Date": { 79 | "S": "2020-04-11T09:25:00" 80 | }, 81 | "State": { 82 | "S": "WARNING2" 83 | } 84 | }, 85 | { 86 | "DeviceID": { 87 | "S": "d#54321" 88 | }, 89 | "Date": { 90 | "S": "2020-04-11T09:30:00" 91 | }, 92 | "State": { 93 | "S": "NORMAL" 94 | } 95 | }, 96 | { 97 | "DeviceID": { 98 | "S": "d#54321" 99 | }, 100 | "Date": { 101 | "S": "2020-04-11T05:50:00" 102 | }, 103 | "State": { 104 | "S": "WARNING3" 105 | } 106 | }, 107 | { 108 | "DeviceID": { 109 | "S": "d#54321" 110 | }, 111 | "Date": { 112 | "S": "2020-04-11T05:55:00" 113 | }, 114 | "State": { 115 | "S": "WARNING3" 116 | } 117 | }, 118 | { 119 | "DeviceID": { 120 | "S": "d#54321" 121 | }, 122 | "Date": { 123 | "S": "2020-04-11T06:00:00" 124 | }, 125 | "State": { 126 | "S": "NORMAL" 127 | } 128 | }, 129 | { 130 | "DeviceID": { 131 | "S": "d#11223" 132 | }, 133 | "Date": { 134 | "S": "2020-04-27T16:10:00" 135 | }, 136 | "State": { 137 | "S": "WARNING4" 138 | } 139 | }, 140 | { 141 | "DeviceID": { 142 | "S": "d#11223" 143 | }, 144 | "Date": { 145 | "S": "2020-04-27T16:15:00" 146 | }, 147 | "State": { 148 | "S": "WARNING4" 149 | } 150 | } 151 | ], 152 | "DataAccess": { 153 | "MySql": {} 154 | } 155 | } 156 | ] 157 | } -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 10, 2020, 12:13 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "State", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Detail", 30 | "AttributeType": "M" 31 | } 32 | ], 33 | "TableData": [ 34 | { 35 | "DeviceID": { 36 | "S": "d#12345" 37 | }, 38 | "Date": { 39 | "S": "2020-04-24T14:40:00" 40 | }, 41 | "State": { 42 | "S": "WARNING1" 43 | } 44 | }, 45 | { 46 | "DeviceID": { 47 | "S": "d#12345" 48 | }, 49 | "Date": { 50 | "S": "2020-04-24T14:45:00" 51 | }, 52 | "State": { 53 | "S": "WARNING1" 54 | } 55 | }, 56 | { 57 | "DeviceID": { 58 | "S": "d#12345" 59 | }, 60 | "Date": { 61 | "S": "2020-04-24T14:50:00" 62 | }, 63 | "State": { 64 | "S": "WARNING1" 65 | } 66 | }, 67 | { 68 | "DeviceID": { 69 | "S": "d#12345" 70 | }, 71 | "Date": { 72 | "S": "2020-04-24T14:55:00" 73 | }, 74 | "State": { 75 | "S": "NORMAL" 76 | }, 77 | "Detail": { 78 | "M": { 79 | "Detail1": { 80 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 81 | }, 82 | "Detail2": { 83 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 84 | }, 85 | "Detail3": { 86 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 87 | }, 88 | "Detail4": { 89 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 90 | }, 91 | "Detail11": { 92 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 93 | }, 94 | "Detail12": { 95 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 96 | }, 97 | "Detail13": { 98 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 99 | }, 100 | "Detail14": { 101 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 102 | }, 103 | "Detail21": { 104 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 105 | }, 106 | "Detail22": { 107 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 108 | }, 109 | "Detail23": { 110 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 111 | }, 112 | "Detail24": { 113 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 114 | }, 115 | "Detail31": { 116 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 117 | }, 118 | "Detail32": { 119 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 120 | }, 121 | "Detail33": { 122 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item." 123 | }, 124 | "Detail34": { 125 | "S": "This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. This is just a test to increase the size of item. " 126 | } 127 | } 128 | } 129 | }, 130 | { 131 | "DeviceID": { 132 | "S": "d#54321" 133 | }, 134 | "Date": { 135 | "S": "2020-04-11T09:25:00" 136 | }, 137 | "State": { 138 | "S": "WARNING2" 139 | } 140 | }, 141 | { 142 | "DeviceID": { 143 | "S": "d#54321" 144 | }, 145 | "Date": { 146 | "S": "2020-04-11T09:30:00" 147 | }, 148 | "State": { 149 | "S": "NORMAL" 150 | } 151 | }, 152 | { 153 | "DeviceID": { 154 | "S": "d#54321" 155 | }, 156 | "Date": { 157 | "S": "2020-04-11T05:50:00" 158 | }, 159 | "State": { 160 | "S": "WARNING3" 161 | } 162 | }, 163 | { 164 | "DeviceID": { 165 | "S": "d#54321" 166 | }, 167 | "Date": { 168 | "S": "2020-04-11T05:55:00" 169 | }, 170 | "State": { 171 | "S": "WARNING3" 172 | } 173 | }, 174 | { 175 | "DeviceID": { 176 | "S": "d#54321" 177 | }, 178 | "Date": { 179 | "S": "2020-04-11T06:00:00" 180 | }, 181 | "State": { 182 | "S": "NORMAL" 183 | } 184 | }, 185 | { 186 | "DeviceID": { 187 | "S": "d#11223" 188 | }, 189 | "Date": { 190 | "S": "2020-04-27T16:10:00" 191 | }, 192 | "State": { 193 | "S": "WARNING4" 194 | } 195 | }, 196 | { 197 | "DeviceID": { 198 | "S": "d#11223" 199 | }, 200 | "Date": { 201 | "S": "2020-04-27T16:15:00" 202 | }, 203 | "State": { 204 | "S": "WARNING4" 205 | } 206 | } 207 | ], 208 | "DataAccess": { 209 | "MySql": {} 210 | } 211 | } 212 | ] 213 | } -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_4.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 10, 2020, 12:13 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "State#Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "Operator", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Date", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "State", 34 | "AttributeType": "S" 35 | } 36 | ], 37 | "TableData": [ 38 | { 39 | "DeviceID": { 40 | "S": "d#12345" 41 | }, 42 | "State#Date": { 43 | "S": "WARNING1#2020-04-24T14:40:00" 44 | }, 45 | "Operator": { 46 | "S": "Liz" 47 | }, 48 | "Date": { 49 | "S": "2020-04-24T14:40:00" 50 | }, 51 | "State": { 52 | "S": "WARNING1" 53 | } 54 | }, 55 | { 56 | "DeviceID": { 57 | "S": "d#12345" 58 | }, 59 | "State#Date": { 60 | "S": "WARNING1#2020-04-24T14:45:00" 61 | }, 62 | "Operator": { 63 | "S": "Liz" 64 | }, 65 | "Date": { 66 | "S": "2020-04-24T14:45:00" 67 | }, 68 | "State": { 69 | "S": "WARNING1" 70 | } 71 | }, 72 | { 73 | "DeviceID": { 74 | "S": "d#12345" 75 | }, 76 | "State#Date": { 77 | "S": "WARNING1#2020-04-24T14:50:00" 78 | }, 79 | "Operator": { 80 | "S": "Liz" 81 | }, 82 | "Date": { 83 | "S": "2020-04-24T14:50:00" 84 | }, 85 | "State": { 86 | "S": "WARNING1" 87 | } 88 | }, 89 | { 90 | "DeviceID": { 91 | "S": "d#12345" 92 | }, 93 | "State#Date": { 94 | "S": "NORMAL#2020-04-24T14:55:00" 95 | }, 96 | "Operator": { 97 | "S": "Liz" 98 | }, 99 | "Date": { 100 | "S": "2020-04-24T14:55:00" 101 | }, 102 | "State": { 103 | "S": "NORMAL" 104 | } 105 | }, 106 | { 107 | "DeviceID": { 108 | "S": "d#54321" 109 | }, 110 | "State#Date": { 111 | "S": "WARNING2#2020-04-11T09:25:00" 112 | }, 113 | "Operator": { 114 | "S": "Sue" 115 | }, 116 | "Date": { 117 | "S": "2020-04-11T09:25:00" 118 | }, 119 | "State": { 120 | "S": "WARNING2" 121 | } 122 | }, 123 | { 124 | "DeviceID": { 125 | "S": "d#54321" 126 | }, 127 | "State#Date": { 128 | "S": "NORMAL#2020-04-11T09:30:00" 129 | }, 130 | "Operator": { 131 | "S": "Sue" 132 | }, 133 | "Date": { 134 | "S": "2020-04-11T09:30:00" 135 | }, 136 | "State": { 137 | "S": "NORMAL" 138 | } 139 | }, 140 | { 141 | "DeviceID": { 142 | "S": "d#54321" 143 | }, 144 | "State#Date": { 145 | "S": "WARNING3#2020-04-11T05:50:00" 146 | }, 147 | "Operator": { 148 | "S": "Sue" 149 | }, 150 | "Date": { 151 | "S": "2020-04-11T05:50:00" 152 | }, 153 | "State": { 154 | "S": "WARNING3" 155 | } 156 | }, 157 | { 158 | "DeviceID": { 159 | "S": "d#54321" 160 | }, 161 | "State#Date": { 162 | "S": "WARNING3#2020-04-11T05:55:00" 163 | }, 164 | "Operator": { 165 | "S": "Liz" 166 | }, 167 | "Date": { 168 | "S": "2020-04-11T05:55:00" 169 | }, 170 | "State": { 171 | "S": "WARNING3" 172 | } 173 | }, 174 | { 175 | "DeviceID": { 176 | "S": "d#54321" 177 | }, 178 | "State#Date": { 179 | "S": "NORMAL#2020-04-11T06:00:00" 180 | }, 181 | "Operator": { 182 | "S": "Liz" 183 | }, 184 | "Date": { 185 | "S": "2020-04-11T06:00:00" 186 | }, 187 | "State": { 188 | "S": "NORMAL" 189 | } 190 | }, 191 | { 192 | "DeviceID": { 193 | "S": "d#11223" 194 | }, 195 | "State#Date": { 196 | "S": "WARNING4#2020-04-27T16:10:00" 197 | }, 198 | "Operator": { 199 | "S": "Sue" 200 | }, 201 | "Date": { 202 | "S": "2020-04-27T16:10:00" 203 | }, 204 | "State": { 205 | "S": "WARNING4" 206 | } 207 | }, 208 | { 209 | "DeviceID": { 210 | "S": "d#11223" 211 | }, 212 | "State#Date": { 213 | "S": "WARNING4#2020-04-27T16:15:00" 214 | }, 215 | "Operator": { 216 | "S": "Sue" 217 | }, 218 | "Date": { 219 | "S": "2020-04-27T16:15:00" 220 | }, 221 | "State": { 222 | "S": "WARNING4" 223 | } 224 | } 225 | ], 226 | "DataAccess": { 227 | "MySql": {} 228 | } 229 | } 230 | ] 231 | } -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_5.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 11, 2020, 04:41 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "State#Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "Operator", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Date", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "State", 34 | "AttributeType": "S" 35 | } 36 | ], 37 | "GlobalSecondaryIndexes": [ 38 | { 39 | "IndexName": "GSI1", 40 | "KeyAttributes": { 41 | "PartitionKey": { 42 | "AttributeName": "Operator", 43 | "AttributeType": "S" 44 | }, 45 | "SortKey": { 46 | "AttributeName": "Date", 47 | "AttributeType": "S" 48 | } 49 | }, 50 | "Projection": { 51 | "ProjectionType": "ALL" 52 | } 53 | } 54 | ], 55 | "TableData": [ 56 | { 57 | "DeviceID": { 58 | "S": "d#12345" 59 | }, 60 | "State#Date": { 61 | "S": "WARNING1#2020-04-24T14:40:00" 62 | }, 63 | "Operator": { 64 | "S": "Liz" 65 | }, 66 | "Date": { 67 | "S": "2020-04-24T14:40:00" 68 | }, 69 | "State": { 70 | "S": "WARNING1" 71 | } 72 | }, 73 | { 74 | "DeviceID": { 75 | "S": "d#12345" 76 | }, 77 | "State#Date": { 78 | "S": "WARNING1#2020-04-24T14:45:00" 79 | }, 80 | "Operator": { 81 | "S": "Liz" 82 | }, 83 | "Date": { 84 | "S": "2020-04-24T14:45:00" 85 | }, 86 | "State": { 87 | "S": "WARNING1" 88 | } 89 | }, 90 | { 91 | "DeviceID": { 92 | "S": "d#12345" 93 | }, 94 | "State#Date": { 95 | "S": "WARNING1#2020-04-24T14:50:00" 96 | }, 97 | "Operator": { 98 | "S": "Liz" 99 | }, 100 | "Date": { 101 | "S": "2020-04-24T14:50:00" 102 | }, 103 | "State": { 104 | "S": "WARNING1" 105 | } 106 | }, 107 | { 108 | "DeviceID": { 109 | "S": "d#12345" 110 | }, 111 | "State#Date": { 112 | "S": "NORMAL#2020-04-24T14:55:00" 113 | }, 114 | "Operator": { 115 | "S": "Liz" 116 | }, 117 | "Date": { 118 | "S": "2020-04-24T14:55:00" 119 | }, 120 | "State": { 121 | "S": "NORMAL" 122 | } 123 | }, 124 | { 125 | "DeviceID": { 126 | "S": "d#54321" 127 | }, 128 | "State#Date": { 129 | "S": "WARNING2#2020-04-11T09:25:00" 130 | }, 131 | "Operator": { 132 | "S": "Sue" 133 | }, 134 | "Date": { 135 | "S": "2020-04-11T09:25:00" 136 | }, 137 | "State": { 138 | "S": "WARNING2" 139 | } 140 | }, 141 | { 142 | "DeviceID": { 143 | "S": "d#54321" 144 | }, 145 | "State#Date": { 146 | "S": "NORMAL#2020-04-11T09:30:00" 147 | }, 148 | "Operator": { 149 | "S": "Sue" 150 | }, 151 | "Date": { 152 | "S": "2020-04-11T09:30:00" 153 | }, 154 | "State": { 155 | "S": "NORMAL" 156 | } 157 | }, 158 | { 159 | "DeviceID": { 160 | "S": "d#54321" 161 | }, 162 | "State#Date": { 163 | "S": "WARNING3#2020-04-11T05:50:00" 164 | }, 165 | "Operator": { 166 | "S": "Sue" 167 | }, 168 | "Date": { 169 | "S": "2020-04-11T05:50:00" 170 | }, 171 | "State": { 172 | "S": "WARNING3" 173 | } 174 | }, 175 | { 176 | "DeviceID": { 177 | "S": "d#54321" 178 | }, 179 | "State#Date": { 180 | "S": "WARNING3#2020-04-11T05:55:00" 181 | }, 182 | "Operator": { 183 | "S": "Liz" 184 | }, 185 | "Date": { 186 | "S": "2020-04-11T05:55:00" 187 | }, 188 | "State": { 189 | "S": "WARNING3" 190 | } 191 | }, 192 | { 193 | "DeviceID": { 194 | "S": "d#54321" 195 | }, 196 | "State#Date": { 197 | "S": "NORMAL#2020-04-11T06:00:00" 198 | }, 199 | "Operator": { 200 | "S": "Liz" 201 | }, 202 | "Date": { 203 | "S": "2020-04-11T06:00:00" 204 | }, 205 | "State": { 206 | "S": "NORMAL" 207 | } 208 | }, 209 | { 210 | "DeviceID": { 211 | "S": "d#11223" 212 | }, 213 | "State#Date": { 214 | "S": "WARNING4#2020-04-27T16:10:00" 215 | }, 216 | "Operator": { 217 | "S": "Sue" 218 | }, 219 | "Date": { 220 | "S": "2020-04-27T16:10:00" 221 | }, 222 | "State": { 223 | "S": "WARNING4" 224 | } 225 | }, 226 | { 227 | "DeviceID": { 228 | "S": "d#11223" 229 | }, 230 | "State#Date": { 231 | "S": "WARNING4#2020-04-27T16:15:00" 232 | }, 233 | "Operator": { 234 | "S": "Sue" 235 | }, 236 | "Date": { 237 | "S": "2020-04-27T16:15:00" 238 | }, 239 | "State": { 240 | "S": "WARNING4" 241 | } 242 | } 243 | ], 244 | "DataAccess": { 245 | "MySql": {} 246 | } 247 | } 248 | ] 249 | } -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_6.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 11, 2020, 04:43 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "State#Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "Operator", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Date", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "State", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "EscalatedTo", 38 | "AttributeType": "S" 39 | } 40 | ], 41 | "GlobalSecondaryIndexes": [ 42 | { 43 | "IndexName": "GSI1", 44 | "KeyAttributes": { 45 | "PartitionKey": { 46 | "AttributeName": "Operator", 47 | "AttributeType": "S" 48 | }, 49 | "SortKey": { 50 | "AttributeName": "Date", 51 | "AttributeType": "S" 52 | } 53 | }, 54 | "Projection": { 55 | "ProjectionType": "ALL" 56 | } 57 | } 58 | ], 59 | "TableData": [ 60 | { 61 | "DeviceID": { 62 | "S": "d#12345" 63 | }, 64 | "State#Date": { 65 | "S": "WARNING1#2020-04-24T14:40:00" 66 | }, 67 | "Operator": { 68 | "S": "Liz" 69 | }, 70 | "Date": { 71 | "S": "2020-04-24T14:40:00" 72 | }, 73 | "State": { 74 | "S": "WARNING1" 75 | } 76 | }, 77 | { 78 | "DeviceID": { 79 | "S": "d#12345" 80 | }, 81 | "State#Date": { 82 | "S": "WARNING1#2020-04-24T14:45:00" 83 | }, 84 | "Operator": { 85 | "S": "Liz" 86 | }, 87 | "Date": { 88 | "S": "2020-04-24T14:45:00" 89 | }, 90 | "State": { 91 | "S": "WARNING1" 92 | } 93 | }, 94 | { 95 | "DeviceID": { 96 | "S": "d#12345" 97 | }, 98 | "State#Date": { 99 | "S": "WARNING1#2020-04-24T14:50:00" 100 | }, 101 | "Operator": { 102 | "S": "Liz" 103 | }, 104 | "Date": { 105 | "S": "2020-04-24T14:50:00" 106 | }, 107 | "State": { 108 | "S": "WARNING1" 109 | } 110 | }, 111 | { 112 | "DeviceID": { 113 | "S": "d#12345" 114 | }, 115 | "State#Date": { 116 | "S": "NORMAL#2020-04-24T14:55:00" 117 | }, 118 | "Operator": { 119 | "S": "Liz" 120 | }, 121 | "Date": { 122 | "S": "2020-04-24T14:55:00" 123 | }, 124 | "State": { 125 | "S": "NORMAL" 126 | } 127 | }, 128 | { 129 | "DeviceID": { 130 | "S": "d#54321" 131 | }, 132 | "State#Date": { 133 | "S": "WARNING2#2020-04-11T09:25:00" 134 | }, 135 | "Operator": { 136 | "S": "Sue" 137 | }, 138 | "Date": { 139 | "S": "2020-04-11T09:25:00" 140 | }, 141 | "State": { 142 | "S": "WARNING2" 143 | } 144 | }, 145 | { 146 | "DeviceID": { 147 | "S": "d#54321" 148 | }, 149 | "State#Date": { 150 | "S": "NORMAL#2020-04-11T09:30:00" 151 | }, 152 | "Operator": { 153 | "S": "Sue" 154 | }, 155 | "Date": { 156 | "S": "2020-04-11T09:30:00" 157 | }, 158 | "State": { 159 | "S": "NORMAL" 160 | } 161 | }, 162 | { 163 | "DeviceID": { 164 | "S": "d#54321" 165 | }, 166 | "State#Date": { 167 | "S": "WARNING3#2020-04-11T05:50:00" 168 | }, 169 | "Operator": { 170 | "S": "Sue" 171 | }, 172 | "Date": { 173 | "S": "2020-04-11T05:50:00" 174 | }, 175 | "State": { 176 | "S": "WARNING3" 177 | } 178 | }, 179 | { 180 | "DeviceID": { 181 | "S": "d#54321" 182 | }, 183 | "State#Date": { 184 | "S": "WARNING3#2020-04-11T05:55:00" 185 | }, 186 | "Operator": { 187 | "S": "Liz" 188 | }, 189 | "Date": { 190 | "S": "2020-04-11T05:55:00" 191 | }, 192 | "State": { 193 | "S": "WARNING3" 194 | } 195 | }, 196 | { 197 | "DeviceID": { 198 | "S": "d#54321" 199 | }, 200 | "State#Date": { 201 | "S": "NORMAL#2020-04-11T06:00:00" 202 | }, 203 | "Operator": { 204 | "S": "Liz" 205 | }, 206 | "Date": { 207 | "S": "2020-04-11T06:00:00" 208 | }, 209 | "State": { 210 | "S": "NORMAL" 211 | } 212 | }, 213 | { 214 | "DeviceID": { 215 | "S": "d#11223" 216 | }, 217 | "State#Date": { 218 | "S": "WARNING4#2020-04-27T16:10:00" 219 | }, 220 | "Operator": { 221 | "S": "Sue" 222 | }, 223 | "Date": { 224 | "S": "2020-04-27T16:10:00" 225 | }, 226 | "State": { 227 | "S": "WARNING4" 228 | } 229 | }, 230 | { 231 | "DeviceID": { 232 | "S": "d#11223" 233 | }, 234 | "State#Date": { 235 | "S": "WARNING4#2020-04-27T16:15:00" 236 | }, 237 | "Operator": { 238 | "S": "Sue" 239 | }, 240 | "Date": { 241 | "S": "2020-04-27T16:15:00" 242 | }, 243 | "State": { 244 | "S": "WARNING4" 245 | }, 246 | "EscalatedTo": { 247 | "S": "Sara" 248 | } 249 | } 250 | ], 251 | "DataAccess": { 252 | "MySql": {} 253 | } 254 | } 255 | ] 256 | } -------------------------------------------------------------------------------- /examples/device-state-log/json/DeviceStateLog_7.json: -------------------------------------------------------------------------------- 1 | { 2 | "ModelName": "DeviceStateLog", 3 | "ModelMetadata": { 4 | "Author": "Samaneh Utter", 5 | "DateCreated": "Apr 24, 2020, 02:40 PM", 6 | "DateLastModified": "Sep 11, 2020, 04:44 PM", 7 | "Description": "This data model show case several NoSQL design patterns for Amazon DynamoDB for DeviceStateLog example.", 8 | "Version": "1.0" 9 | }, 10 | "DataModel": [ 11 | { 12 | "TableName": "DeviceStateLog", 13 | "KeyAttributes": { 14 | "PartitionKey": { 15 | "AttributeName": "DeviceID", 16 | "AttributeType": "S" 17 | }, 18 | "SortKey": { 19 | "AttributeName": "State#Date", 20 | "AttributeType": "S" 21 | } 22 | }, 23 | "NonKeyAttributes": [ 24 | { 25 | "AttributeName": "Operator", 26 | "AttributeType": "S" 27 | }, 28 | { 29 | "AttributeName": "Date", 30 | "AttributeType": "S" 31 | }, 32 | { 33 | "AttributeName": "State", 34 | "AttributeType": "S" 35 | }, 36 | { 37 | "AttributeName": "EscalatedTo", 38 | "AttributeType": "S" 39 | } 40 | ], 41 | "GlobalSecondaryIndexes": [ 42 | { 43 | "IndexName": "GSI1", 44 | "KeyAttributes": { 45 | "PartitionKey": { 46 | "AttributeName": "Operator", 47 | "AttributeType": "S" 48 | }, 49 | "SortKey": { 50 | "AttributeName": "Date", 51 | "AttributeType": "S" 52 | } 53 | }, 54 | "Projection": { 55 | "ProjectionType": "ALL" 56 | } 57 | }, 58 | { 59 | "IndexName": "GSI2", 60 | "KeyAttributes": { 61 | "PartitionKey": { 62 | "AttributeName": "EscalatedTo", 63 | "AttributeType": "S" 64 | }, 65 | "SortKey": { 66 | "AttributeName": "State#Date", 67 | "AttributeType": "S" 68 | } 69 | }, 70 | "Projection": { 71 | "ProjectionType": "ALL" 72 | } 73 | } 74 | ], 75 | "TableData": [ 76 | { 77 | "DeviceID": { 78 | "S": "d#12345" 79 | }, 80 | "State#Date": { 81 | "S": "WARNING1#2020-04-24T14:40:00" 82 | }, 83 | "Operator": { 84 | "S": "Liz" 85 | }, 86 | "Date": { 87 | "S": "2020-04-24T14:40:00" 88 | }, 89 | "State": { 90 | "S": "WARNING1" 91 | } 92 | }, 93 | { 94 | "DeviceID": { 95 | "S": "d#12345" 96 | }, 97 | "State#Date": { 98 | "S": "WARNING1#2020-04-24T14:45:00" 99 | }, 100 | "Operator": { 101 | "S": "Liz" 102 | }, 103 | "Date": { 104 | "S": "2020-04-24T14:45:00" 105 | }, 106 | "State": { 107 | "S": "WARNING1" 108 | } 109 | }, 110 | { 111 | "DeviceID": { 112 | "S": "d#12345" 113 | }, 114 | "State#Date": { 115 | "S": "WARNING1#2020-04-24T14:50:00" 116 | }, 117 | "Operator": { 118 | "S": "Liz" 119 | }, 120 | "Date": { 121 | "S": "2020-04-24T14:50:00" 122 | }, 123 | "State": { 124 | "S": "WARNING1" 125 | } 126 | }, 127 | { 128 | "DeviceID": { 129 | "S": "d#12345" 130 | }, 131 | "State#Date": { 132 | "S": "NORMAL#2020-04-24T14:55:00" 133 | }, 134 | "Operator": { 135 | "S": "Liz" 136 | }, 137 | "Date": { 138 | "S": "2020-04-24T14:55:00" 139 | }, 140 | "State": { 141 | "S": "NORMAL" 142 | } 143 | }, 144 | { 145 | "DeviceID": { 146 | "S": "d#54321" 147 | }, 148 | "State#Date": { 149 | "S": "WARNING2#2020-04-11T09:25:00" 150 | }, 151 | "Operator": { 152 | "S": "Sue" 153 | }, 154 | "Date": { 155 | "S": "2020-04-11T09:25:00" 156 | }, 157 | "State": { 158 | "S": "WARNING2" 159 | } 160 | }, 161 | { 162 | "DeviceID": { 163 | "S": "d#54321" 164 | }, 165 | "State#Date": { 166 | "S": "NORMAL#2020-04-11T09:30:00" 167 | }, 168 | "Operator": { 169 | "S": "Sue" 170 | }, 171 | "Date": { 172 | "S": "2020-04-11T09:30:00" 173 | }, 174 | "State": { 175 | "S": "NORMAL" 176 | } 177 | }, 178 | { 179 | "DeviceID": { 180 | "S": "d#54321" 181 | }, 182 | "State#Date": { 183 | "S": "WARNING3#2020-04-11T05:50:00" 184 | }, 185 | "Operator": { 186 | "S": "Sue" 187 | }, 188 | "Date": { 189 | "S": "2020-04-11T05:50:00" 190 | }, 191 | "State": { 192 | "S": "WARNING3" 193 | } 194 | }, 195 | { 196 | "DeviceID": { 197 | "S": "d#54321" 198 | }, 199 | "State#Date": { 200 | "S": "WARNING3#2020-04-11T05:55:00" 201 | }, 202 | "Operator": { 203 | "S": "Liz" 204 | }, 205 | "Date": { 206 | "S": "2020-04-11T05:55:00" 207 | }, 208 | "State": { 209 | "S": "WARNING3" 210 | } 211 | }, 212 | { 213 | "DeviceID": { 214 | "S": "d#54321" 215 | }, 216 | "State#Date": { 217 | "S": "NORMAL#2020-04-11T06:00:00" 218 | }, 219 | "Operator": { 220 | "S": "Liz" 221 | }, 222 | "Date": { 223 | "S": "2020-04-11T06:00:00" 224 | }, 225 | "State": { 226 | "S": "NORMAL" 227 | } 228 | }, 229 | { 230 | "DeviceID": { 231 | "S": "d#11223" 232 | }, 233 | "State#Date": { 234 | "S": "WARNING4#2020-04-27T16:10:00" 235 | }, 236 | "Operator": { 237 | "S": "Sue" 238 | }, 239 | "Date": { 240 | "S": "2020-04-27T16:10:00" 241 | }, 242 | "State": { 243 | "S": "WARNING4" 244 | } 245 | }, 246 | { 247 | "DeviceID": { 248 | "S": "d#11223" 249 | }, 250 | "State#Date": { 251 | "S": "WARNING4#2020-04-27T16:15:00" 252 | }, 253 | "Operator": { 254 | "S": "Sue" 255 | }, 256 | "Date": { 257 | "S": "2020-04-27T16:15:00" 258 | }, 259 | "State": { 260 | "S": "WARNING4" 261 | }, 262 | "EscalatedTo": { 263 | "S": "Sara" 264 | } 265 | } 266 | ], 267 | "DataAccess": { 268 | "MySql": {} 269 | } 270 | } 271 | ] 272 | } -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_1.png -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_2_composite_sk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_2_composite_sk.png -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_3.png -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_GSI1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_GSI1_1.png -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_GSI2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_GSI2.png -------------------------------------------------------------------------------- /examples/device-state-log/resources/DeviceStateLog_Table_GSI2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/device-state-log/resources/DeviceStateLog_Table_GSI2.png -------------------------------------------------------------------------------- /examples/version-control/README.md: -------------------------------------------------------------------------------- 1 | # How to implement version control using Amazon DynamoDB 2 | 3 | Please read this blog post for detailed description about how to design and implement time-based and number-based version using Amazon DynamoDB. https://aws.amazon.com/blogs/database/implementing-version-control-using-amazon-dynamodb/ 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/README.md: -------------------------------------------------------------------------------- 1 | # How to implement version control using Amazon DynamoDB 2 | 3 | Please read this blog post for detailed description about how to design and implement time-based and number-based version using Amazon DynamoDB. https://aws.amazon.com/blogs/database/implementing-version-control-using-amazon-dynamodb/ 4 | 5 | 6 | ## Deployment 7 | 8 | First and foremost, you need a S3 bucket where you can upload the Lambda functions packaged as ZIP before you deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one: 9 | 10 | ```bash 11 | aws s3 mb s3://BUCKET_NAME 12 | ``` 13 | 14 | Now build your Lambda function 15 | 16 | ```bash 17 | sam build 18 | ``` 19 | 20 | Provided you have a S3 bucket created, run the following command to package our Lambda function to S3: 21 | 22 | ```bash 23 | sam package \ 24 | --output-template-file packaged.yaml \ 25 | --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME 26 | ``` 27 | 28 | Next, the following command will create a Cloudformation Stack and deploy your SAM resources. 29 | 30 | ```bash 31 | sam deploy \ 32 | --template-file packaged.yaml \ 33 | --stack-name number-based-atomic-counters-version-control \ 34 | --capabilities CAPABILITY_IAM 35 | ``` 36 | 37 | > **See [Serverless Application Model (SAM) HOW TO Guide](https://github.com/awslabs/serverless-application-model/blob/master/HOWTO.md) for more details in how to get started.** 38 | 39 | 40 | ## Usage 41 | 42 | First, run **NumberBased-AtomicCounters-AddEquipment** function with this test event: 43 | 44 | ```json 45 | { 46 | "ID": "Equipment#1", 47 | "Name": "EquipmentName", 48 | "FactoryID": "F#12345", 49 | "LineID": "L#12345" 50 | } 51 | ``` 52 | 53 | Next, use the below test event for running **NumberBased-AtomicCounters-AddNewVersion** function. Add as many versions as you want for an equipment, by changing the test event: 54 | 55 | ```json 56 | { 57 | "ID": "Equipment#1", 58 | "State": "WARNING1", 59 | "Time": "2020-11-10T09:00:00" 60 | } 61 | ``` 62 | 63 | Then, to retrieve the latest version, run **NumberBased-AtomicCounters-GetLatestVersion** function with the following test event: 64 | 65 | ```json 66 | { 67 | "ID": "Equipment#1" 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/add_equipment/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries = { 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb', config = conf) 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Add the new equipment item 19 | table.put_item( 20 | Item = { 21 | 'PK': event['ID'], 22 | 'SK': 'Metadata', 23 | 'Name': event['Name'], 24 | 'FactoryID': event['FactoryID'], 25 | 'LineID': event['LineID'] 26 | } 27 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/add_equipment/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/atomic-counters/src/add_equipment/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/add_new_version/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries={ 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb') 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Update the item that contains the latest version and content 19 | response = table.update_item( 20 | Key={ 21 | 'PK': event['ID'], 22 | 'SK': 'v0' 23 | }, 24 | # Atomic counter is used to increment the latest version 25 | UpdateExpression='SET #time = :time, #state = :state, Latest = if_not_exists(Latest, :val0) + :val1', 26 | ExpressionAttributeNames={ 27 | '#time': 'Time', 28 | '#state': 'State' 29 | }, 30 | ExpressionAttributeValues={ 31 | ':time': event['Time'], 32 | ':state': event['State'], 33 | ':val0': 0, 34 | ':val1': 1 35 | }, 36 | ReturnValues='UPDATED_NEW' # return the affected attribute after the update 37 | ) 38 | 39 | # Get the updated version 40 | latest_version = response['Attributes']['Latest'] 41 | 42 | # Add the new item with the latest version 43 | table.put_item( 44 | Item={ 45 | 'PK': event['ID'], 46 | 'SK': 'v' + str(latest_version), 47 | 'Time': event['Time'], 48 | 'State': event['State'] 49 | } 50 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/add_new_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/atomic-counters/src/add_new_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/get_latest_version/main.py: -------------------------------------------------------------------------------- 1 | import decimal 2 | import json 3 | import os 4 | import boto3 5 | from botocore.config import Config 6 | 7 | conf = Config( 8 | retries = { 9 | 'max_attempts': 1, 10 | 'mode': 'standard' 11 | } 12 | ) 13 | 14 | TABLE_NAME = os.environ['TABLE_NAME'] 15 | 16 | # Helper class to convert a DynamoDB item to JSON. 17 | class DecimalEncoder(json.JSONEncoder): 18 | def default(self, o): 19 | if isinstance(o, decimal.Decimal): 20 | if abs(o) % 1 > 0: 21 | return float(o) 22 | else: 23 | return int(o) 24 | return super(DecimalEncoder, self).default(o) 25 | 26 | def handler(event, _): 27 | ddb = boto3.resource('dynamodb', config = conf) 28 | table = ddb.Table(TABLE_NAME) 29 | 30 | # Retrieve the latest state data 31 | response = table.get_item( 32 | Key={ 33 | 'PK': event['ID'], 34 | 'SK': 'v0' 35 | } 36 | ) 37 | item = response['Item'] 38 | print(json.dumps(item, indent=4, cls=DecimalEncoder)) 39 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/src/get_latest_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/atomic-counters/src/get_latest_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/atomic-counters/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | Number-based version, implementing by Atomic Counters 5 | 6 | Sample SAM Template for number-based versioning solutions using Amazon DynamoDB. 7 | 8 | Parameters: 9 | Solution: 10 | Type: String 11 | Default: NumberBased-AtomicCounters 12 | Description: Implementing Number-based versioning by Atomic Counters 13 | 14 | Globals: 15 | Function: 16 | Runtime: python3.8 17 | Handler: main.handler 18 | Timeout: 30 19 | Environment: 20 | Variables: 21 | TABLE_NAME: !Ref VersionTable 22 | 23 | Resources: 24 | ################### 25 | ### Functions ### 26 | ################### 27 | AddEquipmentFunction: 28 | Type: AWS::Serverless::Function 29 | Properties: 30 | FunctionName: !Sub "${Solution}-AddEquipment" 31 | CodeUri: src/add_equipment/ 32 | Role: !GetAtt AddEquipmentRole.Arn 33 | 34 | AddNewVersionFunction: 35 | Type: AWS::Serverless::Function 36 | Properties: 37 | FunctionName: !Sub "${Solution}-AddNewVersion" 38 | CodeUri: src/add_new_version/ 39 | Role: !GetAtt AddNewVersionRole.Arn 40 | 41 | GetLatestVersionFunction: 42 | Type: AWS::Serverless::Function 43 | Properties: 44 | FunctionName: !Sub "${Solution}-GetLatestVersion" 45 | CodeUri: src/get_latest_version/ 46 | Role: !GetAtt GetLatestVersionRole.Arn 47 | 48 | ################### 49 | ### Table ### 50 | ################### 51 | VersionTable: 52 | Type: 'AWS::DynamoDB::Table' 53 | Properties: 54 | TableName: !Sub "${Solution}-VersionTable" 55 | ProvisionedThroughput: 56 | WriteCapacityUnits: 5 57 | ReadCapacityUnits: 5 58 | AttributeDefinitions: 59 | - AttributeName: PK 60 | AttributeType: S 61 | - AttributeName: SK 62 | AttributeType: S 63 | KeySchema: 64 | - KeyType: HASH 65 | AttributeName: PK 66 | - KeyType: RANGE 67 | AttributeName: SK 68 | 69 | ################### 70 | ### Roles ### 71 | ################### 72 | AddEquipmentRole: 73 | Type: AWS::IAM::Role 74 | Properties: 75 | RoleName: !Sub "${Solution}-AddEquipmentRole" 76 | AssumeRolePolicyDocument: 77 | Statement: 78 | - Action: 79 | - sts:AssumeRole 80 | Effect: Allow 81 | Principal: 82 | Service: 83 | - lambda.amazonaws.com 84 | Version: 2012-10-17 85 | Path: / 86 | ManagedPolicyArns: 87 | - arn:aws:iam::aws:policy/AWSLambdaExecute 88 | Policies: 89 | - PolicyName: !Sub "${Solution}-AddEquipmentPolicy" 90 | PolicyDocument: 91 | Version: "2012-10-17" 92 | Statement: 93 | - Effect: "Allow" 94 | Action: 95 | - "dynamodb:PutItem" 96 | Resource: !GetAtt VersionTable.Arn 97 | 98 | AddNewVersionRole: 99 | Type: AWS::IAM::Role 100 | Properties: 101 | RoleName: !Sub "${Solution}-AddNewVersionRole" 102 | AssumeRolePolicyDocument: 103 | Statement: 104 | - Action: 105 | - sts:AssumeRole 106 | Effect: Allow 107 | Principal: 108 | Service: 109 | - lambda.amazonaws.com 110 | Version: 2012-10-17 111 | Path: / 112 | ManagedPolicyArns: 113 | - arn:aws:iam::aws:policy/AWSLambdaExecute 114 | Policies: 115 | - PolicyName: !Sub "${Solution}-AddNewVersionPolicy" 116 | PolicyDocument: 117 | Version: "2012-10-17" 118 | Statement: 119 | - Effect: "Allow" 120 | Action: 121 | - "dynamodb:UpdateItem" 122 | - "dynamodb:PutItem" 123 | Resource: !GetAtt VersionTable.Arn 124 | 125 | GetLatestVersionRole: 126 | Type: AWS::IAM::Role 127 | Properties: 128 | RoleName: !Sub "${Solution}-GetLatestVersionRole" 129 | AssumeRolePolicyDocument: 130 | Statement: 131 | - Action: 132 | - sts:AssumeRole 133 | Effect: Allow 134 | Principal: 135 | Service: 136 | - lambda.amazonaws.com 137 | Version: 2012-10-17 138 | Path: / 139 | ManagedPolicyArns: 140 | - arn:aws:iam::aws:policy/AWSLambdaExecute 141 | Policies: 142 | - PolicyName: !Sub "${Solution}-GetLatestVersionPolicy" 143 | PolicyDocument: 144 | Version: "2012-10-17" 145 | Statement: 146 | - Effect: "Allow" 147 | Action: 148 | - "dynamodb:GetItem" 149 | Resource: !GetAtt VersionTable.Arn -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/README.md: -------------------------------------------------------------------------------- 1 | # How to implement version control using Amazon DynamoDB 2 | 3 | Please read this blog post for detailed description about how to design and implement time-based and number-based version using Amazon DynamoDB. https://aws.amazon.com/blogs/database/implementing-version-control-using-amazon-dynamodb/ 4 | 5 | 6 | ## Deployment 7 | 8 | First and foremost, you need a S3 bucket where you can upload the Lambda functions packaged as ZIP before you deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one: 9 | 10 | ```bash 11 | aws s3 mb s3://BUCKET_NAME 12 | ``` 13 | 14 | Now build your Lambda function 15 | 16 | ```bash 17 | sam build 18 | ``` 19 | 20 | Provided you have a S3 bucket created, run the following command to package our Lambda function to S3: 21 | 22 | ```bash 23 | sam package \ 24 | --output-template-file packaged.yaml \ 25 | --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME 26 | ``` 27 | 28 | Next, the following command will create a Cloudformation Stack and deploy your SAM resources. 29 | 30 | ```bash 31 | sam deploy \ 32 | --template-file packaged.yaml \ 33 | --stack-name number-based-dynamodb-streams-version-control \ 34 | --capabilities CAPABILITY_IAM 35 | ``` 36 | 37 | > **See [Serverless Application Model (SAM) HOW TO Guide](https://github.com/awslabs/serverless-application-model/blob/master/HOWTO.md) for more details in how to get started.** 38 | 39 | 40 | ## Usage 41 | 42 | First, run **NumberBased-DynamoDBStreams-AddEquipment** function with this test event: 43 | 44 | ```json 45 | { 46 | "ID": "Equipment#1", 47 | "Name": "EquipmentName", 48 | "FactoryID": "F#12345", 49 | "LineID": "L#12345" 50 | } 51 | ``` 52 | 53 | Next, use the below test event for running **NumberBased-DynamoDBStreams-UpdateLatestVersion** function. Add as many versions as you want for an equipment, by changing the test event: 54 | 55 | ```json 56 | { 57 | "ID": "Equipment#1", 58 | "State": "WARNING1", 59 | "Time": "2020-11-10T09:00:00" 60 | } 61 | ``` 62 | 63 | Check CloudWatch metrics and logs for **NumberBased-DynamoDBStreams-AddNewVersion** function. Then, to retrieve the latest version, run **NumberBased-DynamoDBStreams-GetLatestVersion** function with the following test event: 64 | 65 | ```json 66 | { 67 | "ID": "Equipment#1" 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/add_equipment/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries = { 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb', config = conf) 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Add the new equipment item 19 | table.put_item( 20 | Item = { 21 | 'PK': event['ID'], 22 | 'SK': 'Metadata', 23 | 'Name': event['Name'], 24 | 'FactoryID': event['FactoryID'], 25 | 'LineID': event['LineID'] 26 | } 27 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/add_equipment/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/dynamodb-streams/src/add_equipment/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/add_new_version/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries={ 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb') 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | for record in event['Records']: 19 | if record['dynamodb']['Keys']['SK']['S'] == 'v0': 20 | new_image = record['dynamodb']['NewImage'] 21 | latest_id = new_image['PK']['S'] 22 | latest_version = new_image['Latest']['N'] 23 | latest_time = new_image['Time']['S'] 24 | latest_state = new_image['State']['S'] 25 | 26 | # Add the new item with the latest version 27 | table.put_item( 28 | Item={ 29 | 'PK': latest_id, 30 | 'SK': 'v' + str(latest_version), 31 | 'Time': latest_time, 32 | 'State': latest_state 33 | } 34 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/add_new_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/dynamodb-streams/src/add_new_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/get_latest_version/main.py: -------------------------------------------------------------------------------- 1 | import decimal 2 | import json 3 | import os 4 | import boto3 5 | from botocore.config import Config 6 | 7 | conf = Config( 8 | retries = { 9 | 'max_attempts': 1, 10 | 'mode': 'standard' 11 | } 12 | ) 13 | 14 | TABLE_NAME = os.environ['TABLE_NAME'] 15 | 16 | # Helper class to convert a DynamoDB item to JSON. 17 | class DecimalEncoder(json.JSONEncoder): 18 | def default(self, o): 19 | if isinstance(o, decimal.Decimal): 20 | if abs(o) % 1 > 0: 21 | return float(o) 22 | else: 23 | return int(o) 24 | return super(DecimalEncoder, self).default(o) 25 | 26 | def handler(event, _): 27 | ddb = boto3.resource('dynamodb', config = conf) 28 | table = ddb.Table(TABLE_NAME) 29 | 30 | # Retrieve the latest state data 31 | response = table.get_item( 32 | Key={ 33 | 'PK': event['ID'], 34 | 'SK': 'v0' 35 | } 36 | ) 37 | item = response['Item'] 38 | print(json.dumps(item, indent=4, cls=DecimalEncoder)) 39 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/get_latest_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/dynamodb-streams/src/get_latest_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/update_latest_version/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries={ 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb') 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Update the item that contains the latest version and content 19 | table.update_item( 20 | Key={ 21 | 'PK': event['ID'], 22 | 'SK': 'v0' 23 | }, 24 | # Atomic counter is used to increment the latest version 25 | UpdateExpression='SET #time = :time, #state = :state, Latest = if_not_exists(Latest, :val0) + :val1', 26 | ExpressionAttributeNames={ 27 | '#time': 'Time', 28 | '#state': 'State' 29 | }, 30 | ExpressionAttributeValues={ 31 | ':time': event['Time'], 32 | ':state': event['State'], 33 | ':val0': 0, 34 | ':val1': 1 35 | } 36 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/src/update_latest_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/dynamodb-streams/src/update_latest_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/dynamodb-streams/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | Number-based version, implementing by DynamoDB Streams 5 | 6 | Sample SAM Template for number-based versioning solutions using Amazon DynamoDB. 7 | 8 | Parameters: 9 | Solution: 10 | Type: String 11 | Default: NumberBased-DynamoDBStreams 12 | Description: Implementing Number-based versioning by DynamoDB Streams 13 | 14 | Globals: 15 | Function: 16 | Runtime: python3.8 17 | Handler: main.handler 18 | Timeout: 30 19 | Environment: 20 | Variables: 21 | TABLE_NAME: !Ref VersionTable 22 | 23 | Resources: 24 | ################### 25 | ### Functions ### 26 | ################### 27 | AddEquipmentFunction: 28 | Type: AWS::Serverless::Function 29 | Properties: 30 | FunctionName: !Sub "${Solution}-AddEquipment" 31 | CodeUri: src/add_equipment/ 32 | Role: !GetAtt AddEquipmentRole.Arn 33 | 34 | UpdateLatestVersionFunction: 35 | Type: AWS::Serverless::Function 36 | Properties: 37 | FunctionName: !Sub "${Solution}-UpdateLatestVersion" 38 | CodeUri: src/update_latest_version/ 39 | Role: !GetAtt UpdateLatestVersionRole.Arn 40 | 41 | AddNewVersionFunction: 42 | Type: AWS::Serverless::Function 43 | Properties: 44 | FunctionName: !Sub "${Solution}-AddNewVersion" 45 | CodeUri: src/add_new_version/ 46 | Role: !GetAtt AddNewVersionRole.Arn 47 | Events: 48 | DynamoDBEvent: 49 | Type: DynamoDB 50 | Properties: 51 | Stream: 52 | !GetAtt VersionTable.StreamArn 53 | StartingPosition: TRIM_HORIZON 54 | BatchSize: 10 55 | MaximumBatchingWindowInSeconds: 10 56 | Enabled: true 57 | #ParallelizationFactor: 8 58 | MaximumRetryAttempts: 10 59 | BisectBatchOnFunctionError: true 60 | MaximumRecordAgeInSeconds: 86400 61 | # DLQ 62 | # DestinationConfig: 63 | # OnFailure: 64 | # Type: SQS 65 | # Destination: !GetAtt MySqsQueue.Arn 66 | 67 | GetLatestVersionFunction: 68 | Type: AWS::Serverless::Function 69 | Properties: 70 | FunctionName: !Sub "${Solution}-GetLatestVersion" 71 | CodeUri: src/get_latest_version/ 72 | Role: !GetAtt GetLatestVersionRole.Arn 73 | 74 | ################### 75 | ### Table ### 76 | ################### 77 | VersionTable: 78 | Type: 'AWS::DynamoDB::Table' 79 | Properties: 80 | TableName: !Sub "${Solution}-VersionTable" 81 | ProvisionedThroughput: 82 | WriteCapacityUnits: 5 83 | ReadCapacityUnits: 5 84 | StreamSpecification: 85 | StreamViewType: NEW_AND_OLD_IMAGES 86 | AttributeDefinitions: 87 | - AttributeName: PK 88 | AttributeType: S 89 | - AttributeName: SK 90 | AttributeType: S 91 | KeySchema: 92 | - KeyType: HASH 93 | AttributeName: PK 94 | - KeyType: RANGE 95 | AttributeName: SK 96 | 97 | ################### 98 | ### Roles ### 99 | ################### 100 | AddEquipmentRole: 101 | Type: AWS::IAM::Role 102 | Properties: 103 | RoleName: !Sub "${Solution}-AddEquipmentRole" 104 | AssumeRolePolicyDocument: 105 | Statement: 106 | - Action: 107 | - sts:AssumeRole 108 | Effect: Allow 109 | Principal: 110 | Service: 111 | - lambda.amazonaws.com 112 | Version: 2012-10-17 113 | Path: / 114 | ManagedPolicyArns: 115 | - arn:aws:iam::aws:policy/AWSLambdaExecute 116 | Policies: 117 | - PolicyName: !Sub "${Solution}-AddEquipmentPolicy" 118 | PolicyDocument: 119 | Version: "2012-10-17" 120 | Statement: 121 | - Effect: "Allow" 122 | Action: 123 | - "dynamodb:PutItem" 124 | Resource: !GetAtt VersionTable.Arn 125 | 126 | UpdateLatestVersionRole: 127 | Type: AWS::IAM::Role 128 | Properties: 129 | RoleName: !Sub "${Solution}-UpdateLatestVersionRole" 130 | AssumeRolePolicyDocument: 131 | Statement: 132 | - Action: 133 | - sts:AssumeRole 134 | Effect: Allow 135 | Principal: 136 | Service: 137 | - lambda.amazonaws.com 138 | Version: 2012-10-17 139 | Path: / 140 | ManagedPolicyArns: 141 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 142 | Policies: 143 | - PolicyName: !Sub "${Solution}-UpdateLatestVersionPolicy" 144 | PolicyDocument: 145 | Version: "2012-10-17" 146 | Statement: 147 | - Effect: "Allow" 148 | Action: 149 | - "dynamodb:UpdateItem" 150 | Resource: !GetAtt VersionTable.Arn 151 | 152 | AddNewVersionRole: 153 | Type: AWS::IAM::Role 154 | Properties: 155 | RoleName: !Sub "${Solution}-AddNewVersionRole" 156 | AssumeRolePolicyDocument: 157 | Statement: 158 | - Action: 159 | - sts:AssumeRole 160 | Effect: Allow 161 | Principal: 162 | Service: 163 | - lambda.amazonaws.com 164 | Version: 2012-10-17 165 | Path: / 166 | ManagedPolicyArns: 167 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 168 | - arn:aws:iam::aws:policy/service-role/AWSLambdaDynamoDBExecutionRole 169 | Policies: 170 | - PolicyName: !Sub "${Solution}-AddNewVersionPolicy" 171 | PolicyDocument: 172 | Version: "2012-10-17" 173 | Statement: 174 | - Effect: "Allow" 175 | Action: 176 | - "dynamodb:PutItem" 177 | Resource: !GetAtt VersionTable.Arn 178 | 179 | GetLatestVersionRole: 180 | Type: AWS::IAM::Role 181 | Properties: 182 | RoleName: !Sub "${Solution}-GetLatestVersionRole" 183 | AssumeRolePolicyDocument: 184 | Statement: 185 | - Action: 186 | - sts:AssumeRole 187 | Effect: Allow 188 | Principal: 189 | Service: 190 | - lambda.amazonaws.com 191 | Version: 2012-10-17 192 | Path: / 193 | ManagedPolicyArns: 194 | - arn:aws:iam::aws:policy/AWSLambdaExecute 195 | Policies: 196 | - PolicyName: !Sub "${Solution}-GetLatestVersionPolicy" 197 | PolicyDocument: 198 | Version: "2012-10-17" 199 | Statement: 200 | - Effect: "Allow" 201 | Action: 202 | - "dynamodb:GetItem" 203 | Resource: !GetAtt VersionTable.Arn -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/README.md: -------------------------------------------------------------------------------- 1 | # How to implement version control using Amazon DynamoDB 2 | 3 | Please read this blog post for detailed description about how to design and implement time-based and number-based version using Amazon DynamoDB. https://aws.amazon.com/blogs/database/implementing-version-control-using-amazon-dynamodb/ 4 | 5 | 6 | ## Deployment 7 | 8 | First and foremost, you need a S3 bucket where you can upload the Lambda functions packaged as ZIP before you deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one: 9 | 10 | ```bash 11 | aws s3 mb s3://BUCKET_NAME 12 | ``` 13 | 14 | Now build your Lambda function 15 | 16 | ```bash 17 | sam build 18 | ``` 19 | 20 | Provided you have a S3 bucket created, run the following command to package our Lambda function to S3: 21 | 22 | ```bash 23 | sam package \ 24 | --output-template-file packaged.yaml \ 25 | --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME 26 | ``` 27 | 28 | Next, the following command will create a Cloudformation Stack and deploy your SAM resources. 29 | 30 | ```bash 31 | sam deploy \ 32 | --template-file packaged.yaml \ 33 | --stack-name number-based-transactional-write-version-control \ 34 | --capabilities CAPABILITY_IAM 35 | ``` 36 | 37 | > **See [Serverless Application Model (SAM) HOW TO Guide](https://github.com/awslabs/serverless-application-model/blob/master/HOWTO.md) for more details in how to get started.** 38 | 39 | 40 | ## Usage 41 | 42 | First, run **NumberBased-TransactionalWrite-AddEquipment** function with this test event: 43 | 44 | ```json 45 | { 46 | "ID": "Equipment#1", 47 | "Name": "EquipmentName", 48 | "FactoryID": "F#12345", 49 | "LineID": "L#12345" 50 | } 51 | ``` 52 | 53 | Next, use the below test event for running **NumberBased-TransactionalWrite-AddNewVersion** function. Add as many versions as you want for an equipment, by changing the test event: 54 | 55 | ```json 56 | { 57 | "ID": "Equipment#1", 58 | "State": "WARNING1", 59 | "Time": "2020-11-10T09:00:00" 60 | } 61 | ``` 62 | 63 | Then, to retrieve the latest version, run **NumberBased-TransactionalWrite-GetLatestVersion** function with the following test event: 64 | 65 | ```json 66 | { 67 | "ID": "Equipment#1" 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/add_equipment/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries = { 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb', config = conf) 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Add the new equipment item 19 | table.put_item( 20 | Item = { 21 | 'PK': event['ID'], 22 | 'SK': 'Metadata', 23 | 'Name': event['Name'], 24 | 'FactoryID': event['FactoryID'], 25 | 'LineID': event['LineID'] 26 | } 27 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/add_equipment/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/transactional-write/src/add_equipment/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/add_new_version/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries={ 7 | 'max_attempts': 1, # Find more information about retries here: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | ddb = boto3.client('dynamodb', config=conf) 13 | TABLE_NAME = os.environ['TABLE_NAME'] 14 | 15 | def handler(event, _): 16 | 17 | # Retrieve the latest version 18 | response_latest_version = ddb.get_item( 19 | TableName=TABLE_NAME, 20 | Key={ 21 | 'PK': {'S': event['ID']}, 22 | 'SK': {'S': 'v0'} 23 | } 24 | ) 25 | 26 | latest_version = 0 27 | higher_version = 1 28 | 29 | # Extract 'Latest' from response 30 | if 'Item' in response_latest_version: 31 | latest_version = response_latest_version['Item']['Latest']['N'] 32 | higher_version = int(latest_version) + 1 33 | 34 | # Transactional write where Update and Put are grouped together 35 | ddb.transact_write_items( 36 | TransactItems=[ 37 | { 38 | 'Update': { 39 | 'TableName': TABLE_NAME, 40 | 'Key': { 41 | 'PK': { 42 | 'S': event['ID'] 43 | }, 44 | 'SK': { 45 | 'S': 'v0' 46 | } 47 | }, 48 | # Conditional write makes the update idempotent here since the conditional check is on the same attribute that is being updated. 49 | 'ConditionExpression': 'attribute_not_exists(#latest) OR #latest = :latest', 50 | 'UpdateExpression': 'SET #time = :time, #state = :state, #latest = :higher_version', 51 | 'ExpressionAttributeNames': { 52 | '#latest': 'Latest', 53 | '#time': 'Time', 54 | '#state': 'State' 55 | }, 56 | 'ExpressionAttributeValues': { 57 | ':latest': { 58 | 'N': str(latest_version) 59 | }, 60 | ':higher_version': { 61 | 'N': str(higher_version) 62 | }, 63 | ':time': { 64 | 'S': event['Time'] 65 | }, 66 | ':state': { 67 | 'S': event['State'] 68 | } 69 | } 70 | } 71 | }, 72 | { 73 | 'Put': { 74 | 'TableName': TABLE_NAME, 75 | 'Item': { 76 | 'PK': { 77 | 'S': event['ID'] 78 | }, 79 | 'SK': { 80 | 'S': 'v' + str(higher_version) 81 | }, 82 | 'Time': { 83 | 'S': event['Time'] 84 | }, 85 | 'State': { 86 | 'S': event['State'] 87 | } 88 | } 89 | } 90 | } 91 | ] 92 | ) -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/add_new_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/transactional-write/src/add_new_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/get_latest_version/main.py: -------------------------------------------------------------------------------- 1 | import decimal 2 | import json 3 | import os 4 | import boto3 5 | from botocore.config import Config 6 | 7 | conf = Config( 8 | retries = { 9 | 'max_attempts': 1, 10 | 'mode': 'standard' 11 | } 12 | ) 13 | 14 | TABLE_NAME = os.environ['TABLE_NAME'] 15 | 16 | # Helper class to convert a DynamoDB item to JSON. 17 | class DecimalEncoder(json.JSONEncoder): 18 | def default(self, o): 19 | if isinstance(o, decimal.Decimal): 20 | if abs(o) % 1 > 0: 21 | return float(o) 22 | else: 23 | return int(o) 24 | return super(DecimalEncoder, self).default(o) 25 | 26 | def handler(event, _): 27 | ddb = boto3.resource('dynamodb', config = conf) 28 | table = ddb.Table(TABLE_NAME) 29 | 30 | # Retrieve the latest state data 31 | response = table.get_item( 32 | Key={ 33 | 'PK': event['ID'], 34 | 'SK': 'v0' 35 | } 36 | ) 37 | item = response['Item'] 38 | print(json.dumps(item, indent=4, cls=DecimalEncoder)) 39 | -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/src/get_latest_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/number-based-version/transactional-write/src/get_latest_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/number-based-version/transactional-write/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | Number-based version, implementing by Transactional Write 5 | 6 | Sample SAM Template for number-based versioning solutions using Amazon DynamoDB. 7 | 8 | Parameters: 9 | Solution: 10 | Type: String 11 | Default: NumberBased-TransactionalWrite 12 | Description: Implementing Number-based versioning by Transactional Write 13 | 14 | Globals: 15 | Function: 16 | Runtime: python3.8 17 | Handler: main.handler 18 | Timeout: 30 19 | Environment: 20 | Variables: 21 | TABLE_NAME: !Ref VersionTable 22 | 23 | Resources: 24 | ################### 25 | ### Functions ### 26 | ################### 27 | AddEquipmentFunction: 28 | Type: AWS::Serverless::Function 29 | Properties: 30 | FunctionName: !Sub "${Solution}-AddEquipment" 31 | CodeUri: src/add_equipment/ 32 | Role: !GetAtt AddEquipmentRole.Arn 33 | 34 | AddNewVersionFunction: 35 | Type: AWS::Serverless::Function 36 | Properties: 37 | FunctionName: !Sub "${Solution}-AddNewVersion" 38 | CodeUri: src/add_new_version/ 39 | Role: !GetAtt AddNewVersionRole.Arn 40 | 41 | GetLatestVersionFunction: 42 | Type: AWS::Serverless::Function 43 | Properties: 44 | FunctionName: !Sub "${Solution}-GetLatestVersion" 45 | CodeUri: src/get_latest_version/ 46 | Role: !GetAtt GetLatestVersionRole.Arn 47 | 48 | ################### 49 | ### Table ### 50 | ################### 51 | VersionTable: 52 | Type: 'AWS::DynamoDB::Table' 53 | Properties: 54 | TableName: !Sub "${Solution}-VersionTable" 55 | ProvisionedThroughput: 56 | WriteCapacityUnits: 5 57 | ReadCapacityUnits: 5 58 | AttributeDefinitions: 59 | - AttributeName: PK 60 | AttributeType: S 61 | - AttributeName: SK 62 | AttributeType: S 63 | KeySchema: 64 | - KeyType: HASH 65 | AttributeName: PK 66 | - KeyType: RANGE 67 | AttributeName: SK 68 | 69 | ################### 70 | ### Roles ### 71 | ################### 72 | AddEquipmentRole: 73 | Type: AWS::IAM::Role 74 | Properties: 75 | RoleName: !Sub "${Solution}-AddEquipmentRole" 76 | AssumeRolePolicyDocument: 77 | Statement: 78 | - Action: 79 | - sts:AssumeRole 80 | Effect: Allow 81 | Principal: 82 | Service: 83 | - lambda.amazonaws.com 84 | Version: 2012-10-17 85 | Path: / 86 | ManagedPolicyArns: 87 | - arn:aws:iam::aws:policy/AWSLambdaExecute 88 | Policies: 89 | - PolicyName: !Sub "${Solution}-AddEquipmentPolicy" 90 | PolicyDocument: 91 | Version: "2012-10-17" 92 | Statement: 93 | - Effect: "Allow" 94 | Action: 95 | - "dynamodb:PutItem" 96 | Resource: !GetAtt VersionTable.Arn 97 | 98 | AddNewVersionRole: 99 | Type: AWS::IAM::Role 100 | Properties: 101 | RoleName: !Sub "${Solution}-AddNewVersionRole" 102 | AssumeRolePolicyDocument: 103 | Statement: 104 | - Action: 105 | - sts:AssumeRole 106 | Effect: Allow 107 | Principal: 108 | Service: 109 | - lambda.amazonaws.com 110 | Version: 2012-10-17 111 | Path: / 112 | ManagedPolicyArns: 113 | - arn:aws:iam::aws:policy/AWSLambdaExecute 114 | Policies: 115 | - PolicyName: !Sub "${Solution}-AddNewVersionPolicy" 116 | PolicyDocument: 117 | Version: "2012-10-17" 118 | Statement: 119 | - Effect: "Allow" 120 | Action: 121 | - "dynamodb:GetItem" 122 | - "dynamodb:UpdateItem" 123 | - "dynamodb:PutItem" 124 | Resource: !GetAtt VersionTable.Arn 125 | 126 | GetLatestVersionRole: 127 | Type: AWS::IAM::Role 128 | Properties: 129 | RoleName: !Sub "${Solution}-GetLatestVersionRole" 130 | AssumeRolePolicyDocument: 131 | Statement: 132 | - Action: 133 | - sts:AssumeRole 134 | Effect: Allow 135 | Principal: 136 | Service: 137 | - lambda.amazonaws.com 138 | Version: 2012-10-17 139 | Path: / 140 | ManagedPolicyArns: 141 | - arn:aws:iam::aws:policy/AWSLambdaExecute 142 | Policies: 143 | - PolicyName: !Sub "${Solution}-GetLatestVersionPolicy" 144 | PolicyDocument: 145 | Version: "2012-10-17" 146 | Statement: 147 | - Effect: "Allow" 148 | Action: 149 | - "dynamodb:GetItem" 150 | Resource: !GetAtt VersionTable.Arn -------------------------------------------------------------------------------- /examples/version-control/time-based-version/README.md: -------------------------------------------------------------------------------- 1 | # How to implement version control using Amazon DynamoDB 2 | 3 | Please read this blog post for detailed description about how to design and implement time-based and number-based version using Amazon DynamoDB. https://aws.amazon.com/blogs/database/implementing-version-control-using-amazon-dynamodb/ 4 | 5 | 6 | ## Deployment 7 | 8 | First and foremost, you need a S3 bucket where you can upload the Lambda functions packaged as ZIP before you deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one: 9 | 10 | ```bash 11 | aws s3 mb s3://BUCKET_NAME 12 | ``` 13 | 14 | Now build your Lambda function 15 | 16 | ```bash 17 | sam build 18 | ``` 19 | 20 | Provided you have a S3 bucket created, run the following command to package our Lambda function to S3: 21 | 22 | ```bash 23 | sam package \ 24 | --output-template-file packaged.yaml \ 25 | --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME 26 | ``` 27 | 28 | Next, the following command will create a Cloudformation Stack and deploy your SAM resources. 29 | 30 | ```bash 31 | sam deploy \ 32 | --template-file packaged.yaml \ 33 | --stack-name time-based-version-control \ 34 | --capabilities CAPABILITY_IAM 35 | ``` 36 | 37 | > **See [Serverless Application Model (SAM) HOW TO Guide](https://github.com/awslabs/serverless-application-model/blob/master/HOWTO.md) for more details in how to get started.** 38 | 39 | 40 | ## Usage 41 | 42 | First, run **TimeBased-AddEquipment** function with this test event: 43 | 44 | ```json 45 | { 46 | "ID": "Equipment#1", 47 | "Name": "EquipmentName", 48 | "FactoryID": "F#12345", 49 | "LineID": "L#12345" 50 | } 51 | ``` 52 | 53 | Next, use the below test event for running **TimeBased-AddNewVersion** function. Add as many versions as you want for an equipment, by changing the test event: 54 | 55 | ```json 56 | { 57 | "ID": "Equipment#1", 58 | "State": "WARNING1", 59 | "Time": "2020-11-10T09:00:00" 60 | } 61 | ``` 62 | 63 | Then, to retrieve the latest version, run **TimeBased-GetLatestVersion** function with the following test event: 64 | 65 | ```json 66 | { 67 | "ID": "Equipment#1" 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/add_equipment/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries = { 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb', config = conf) 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Add the new equipment item 19 | table.put_item( 20 | Item = { 21 | 'PK': event['ID'], 22 | 'SK': 'Metadata', 23 | 'Name': event['Name'], 24 | 'FactoryID': event['FactoryID'], 25 | 'LineID': event['LineID'] 26 | } 27 | ) -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/add_equipment/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/time-based-version/src/add_equipment/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/add_new_version/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import boto3 3 | from botocore.config import Config 4 | 5 | conf = Config( 6 | retries = { 7 | 'max_attempts': 1, 8 | 'mode': 'standard' 9 | } 10 | ) 11 | 12 | TABLE_NAME = os.environ['TABLE_NAME'] 13 | 14 | def handler(event, _): 15 | ddb = boto3.resource('dynamodb', config = conf) 16 | table = ddb.Table(TABLE_NAME) 17 | 18 | # Add the new state data item for the equipment 19 | table.put_item( 20 | Item = { 21 | 'PK': event['ID'], 22 | 'SK': event['Time'], 23 | 'State': event['State'] 24 | } 25 | ) -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/add_new_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/time-based-version/src/add_new_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/get_latest_version/main.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import boto3 4 | from botocore.config import Config 5 | from boto3.dynamodb.conditions import Key 6 | 7 | conf = Config( 8 | retries = { 9 | 'max_attempts': 1, 10 | 'mode': 'standard' 11 | } 12 | ) 13 | 14 | TABLE_NAME = os.environ['TABLE_NAME'] 15 | 16 | def handler(event, _): 17 | ddb = boto3.resource('dynamodb', config = conf) 18 | table = ddb.Table(TABLE_NAME) 19 | 20 | # Retrieve the latest state data 21 | response = table.query( 22 | KeyConditionExpression = Key('PK').eq(event['ID']) & Key('SK').begins_with('2'), 23 | # Strongly consistent read 24 | ConsistentRead = True, 25 | # Sort items in descending order 26 | ScanIndexForward = False, 27 | # Specifies the maximum number of items to evaluate 28 | Limit = 1 29 | ) 30 | items = response['Items'] 31 | print(json.dumps(items, indent=4)) -------------------------------------------------------------------------------- /examples/version-control/time-based-version/src/get_latest_version/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/amazon-dynamodb-design-patterns/6dceeaa7818135ef3045f032b6ff93d126f4a539/examples/version-control/time-based-version/src/get_latest_version/requirements.txt -------------------------------------------------------------------------------- /examples/version-control/time-based-version/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: > 4 | Time-based version 5 | 6 | Sample SAM Template for time-based versioning solution using Amazon DynamoDB. 7 | 8 | Parameters: 9 | Solution: 10 | Type: String 11 | Default: TimeBased 12 | Description: Implementing Time-based versioning 13 | 14 | Globals: 15 | Function: 16 | Runtime: python3.8 17 | Handler: main.handler 18 | Timeout: 30 19 | Environment: 20 | Variables: 21 | TABLE_NAME: !Ref VersionTable 22 | 23 | Resources: 24 | ################### 25 | ### Functions ### 26 | ################### 27 | AddEquipmentFunction: 28 | Type: AWS::Serverless::Function 29 | Properties: 30 | FunctionName: !Sub "${Solution}-AddEquipment" 31 | CodeUri: src/add_equipment/ 32 | Role: !GetAtt AddEquipmentRole.Arn 33 | 34 | AddNewVersionFunction: 35 | Type: AWS::Serverless::Function 36 | Properties: 37 | FunctionName: !Sub "${Solution}-AddNewVersion" 38 | CodeUri: src/add_new_version/ 39 | Role: !GetAtt AddNewVersionRole.Arn 40 | 41 | GetLatestVersionFunction: 42 | Type: AWS::Serverless::Function 43 | Properties: 44 | FunctionName: !Sub "${Solution}-GetLatestVersion" 45 | CodeUri: src/get_latest_version/ 46 | Role: !GetAtt GetLatestVersionRole.Arn 47 | 48 | ################### 49 | ### Table ### 50 | ################### 51 | VersionTable: 52 | Type: 'AWS::DynamoDB::Table' 53 | Properties: 54 | TableName: !Sub "${Solution}-VersionTable" 55 | ProvisionedThroughput: 56 | WriteCapacityUnits: 5 57 | ReadCapacityUnits: 5 58 | AttributeDefinitions: 59 | - AttributeName: PK 60 | AttributeType: S 61 | - AttributeName: SK 62 | AttributeType: S 63 | KeySchema: 64 | - KeyType: HASH 65 | AttributeName: PK 66 | - KeyType: RANGE 67 | AttributeName: SK 68 | 69 | ################### 70 | ### Roles ### 71 | ################### 72 | AddEquipmentRole: 73 | Type: AWS::IAM::Role 74 | Properties: 75 | RoleName: !Sub "${Solution}-AddEquipmentRole" 76 | AssumeRolePolicyDocument: 77 | Statement: 78 | - Action: 79 | - sts:AssumeRole 80 | Effect: Allow 81 | Principal: 82 | Service: 83 | - lambda.amazonaws.com 84 | Version: 2012-10-17 85 | Path: / 86 | ManagedPolicyArns: 87 | - arn:aws:iam::aws:policy/AWSLambdaExecute 88 | Policies: 89 | - PolicyName: !Sub "${Solution}-AddEquipmentPolicy" 90 | PolicyDocument: 91 | Version: "2012-10-17" 92 | Statement: 93 | - Effect: "Allow" 94 | Action: 95 | - "dynamodb:PutItem" 96 | Resource: !GetAtt VersionTable.Arn 97 | 98 | AddNewVersionRole: 99 | Type: AWS::IAM::Role 100 | Properties: 101 | RoleName: !Sub "${Solution}-AddNewVersionRole" 102 | AssumeRolePolicyDocument: 103 | Statement: 104 | - Action: 105 | - sts:AssumeRole 106 | Effect: Allow 107 | Principal: 108 | Service: 109 | - lambda.amazonaws.com 110 | Version: 2012-10-17 111 | Path: / 112 | ManagedPolicyArns: 113 | - arn:aws:iam::aws:policy/AWSLambdaExecute 114 | Policies: 115 | - PolicyName: !Sub "${Solution}-AddNewVersionPolicy" 116 | PolicyDocument: 117 | Version: "2012-10-17" 118 | Statement: 119 | - Effect: "Allow" 120 | Action: 121 | - "dynamodb:PutItem" 122 | Resource: !GetAtt VersionTable.Arn 123 | 124 | GetLatestVersionRole: 125 | Type: AWS::IAM::Role 126 | Properties: 127 | RoleName: !Sub "${Solution}-GetLatestVersionRole" 128 | AssumeRolePolicyDocument: 129 | Statement: 130 | - Action: 131 | - sts:AssumeRole 132 | Effect: Allow 133 | Principal: 134 | Service: 135 | - lambda.amazonaws.com 136 | Version: 2012-10-17 137 | Path: / 138 | ManagedPolicyArns: 139 | - arn:aws:iam::aws:policy/AWSLambdaExecute 140 | Policies: 141 | - PolicyName: !Sub "${Solution}-GetLatestVersionPolicy" 142 | PolicyDocument: 143 | Version: "2012-10-17" 144 | Statement: 145 | - Effect: "Allow" 146 | Action: 147 | - "dynamodb:Query" 148 | Resource: !GetAtt VersionTable.Arn --------------------------------------------------------------------------------