Materials https://docs.aws.amazon.com/dynamodb/ Components Attribute - data element Items - collection of attributes Table - collection of items Each item can have its own distinct attributes Usually attributes have only one value Nested attribute (address) are allowed, up to 32 levels deep Primary key Primary key is mandatory identifier for an item in the table Primary key can be a simple one attribute - partition key Composed primary key can be a partition key + sort key . Partition keys can be the same in such case. Primary key attribute can be only string, number or binary Secondary indexes Secondary indexes can be created to query table in addition to queries against the primary key Not necessary if values of primary keys are enough for querying There are global & local secondary indexes, but put Local ones apart, did not get why to use them 20 global secondary indexes are allowed We do not necessarily need indexes, because we can use Scan + FilterExpression, but it is heavy, long and pricy. Better to add an index We can apply global secondary index after table creation Internally every secondary index creates a cloned table keeping it in sync to the original, which leads to double cost on every read & write Local DynamoDB setup Install Java runtime Download local DynamoDb Put into some folder and open it with terminal Run java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar -sharedDb -port 8000 Output Initializing DynamoDB Local with the following configuration: Port: 8000 InMemory: false DbPath: null SharedDb: true shouldDelayTransientStatuses: false CorsParams: * End-point for database is http://localhost:8000 Instal AWS CLI Configure CLI with aws configure after installation Keys to be taken from AWS web site from Account name - Security credentials - Access keys AWS Access Key ID [None]: AKIAIOSFODNN7(example) AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY(example) Default region name [None]: eu-north-1 Default output format [None]: json Check available tables with aws dynamodb list-tables --endpoint-url http://localhost:8000 Output { "TableNames": [] } JavaScript SDK Install DynamoDB Client - AWS SDK for JavaScript v3 and @aws-sdk/lib-dynamodb from AWS SDK for JavaScript v3 . Package.json { "scripts": { "start": "nodemon app.js" }, "dependencies": { "@aws-sdk/client-dynamodb": "^3.72.0", "@aws-sdk/lib-dynamodb": "^3.74.0", "aws-sdk": "^2.1117.0", "express": "^4.17.3" }, "type": "module" } DynamoDBClient // ddbClient.js import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; const region = 'eu-north-1' const endpoint = 'http://localhost:8000' export const ddbClient = new DynamoDBClient({ region, endpoint }) DynamoDBDocumentClient // ddbDocumentClient.js import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb" import { ddbClient } from "./ddbClient.js" const marshallOptions = { convertEmptyValues: false, // Whether to automatically convert empty strings, blobs, and sets to `null`, false, by default. removeUndefinedValues: false, // Whether to remove undefined values while marshalling, false, by default. convertClassInstanceToMap: false, // Whether to convert typeof object to map attribute, false, by default. } const unMarshallOptions = { wrapNumbers: false, // Whether to return numbers as a string instead of converting them to native JavaScript numbers, false, by default. } const translateConfig = { marshallOptions, unMarshallOptions } // Create the DynamoDB document client export const ddbDocClient = DynamoDBDocumentClient.from(ddbClient, translateConfig) List tables // listTables.js import { ListTablesCommand } from '@aws-sdk/client-dynamodb' import { ddbClient } from './ddbClient.js' export const listTables = async () => { try { const data = await ddbClient.send(new ListTablesCommand ({})) console.log('Tables are listed: ', data) return data } catch (err) { console.log('Error in table deletion', err) } } listTables() Create table // createTables.js import { CreateTableCommand } from '@aws-sdk/client-dynamodb' import { ddbClient } from './ddbClient.js' var tableParams1 = { TableName: 'Users', KeySchema: [{ AttributeName: 'email', KeyType: 'HASH' }], AttributeDefinitions: [{ AttributeName: 'email', AttributeType: 'S' }], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, } var tableParams2 = { TableName: 'Logins', KeySchema: [ { AttributeName: 'email', KeyType: 'HASH' }, { AttributeName: 'timestamp', KeyType: 'RANGE' }, ], AttributeDefinitions: [ { AttributeName: 'email', AttributeType: 'S' }, { AttributeName: 'timestamp', AttributeType: 'N' }, ], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, } var tableParams3 = { TableName: 'Supervisors', KeySchema: [{ AttributeName: 'name', KeyType: 'HASH' }], AttributeDefinitions: [ { AttributeName: 'name', AttributeType: 'S' }, { AttributeName: 'company', AttributeType: 'S' }, { AttributeName: 'factory', AttributeType: 'S' }, ], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, GlobalSecondaryIndexes: [ { IndexName: 'FactoryIndex', KeySchema: [ { AttributeName: 'company', KeyType: 'HASH', }, { AttributeName: 'factory', KeyType: 'RANGE', }, ], Projection: { ProjectionType: 'ALL', }, ProvisionedThroughput: { ReadCapacityUnits: 1, WriteCapacityUnits: 1, }, }, ], } var tableParams4 = { TableName: 'Companies', KeySchema: [ { AttributeName: 'name', KeyType: 'HASH' }, { AttributeName: 'subsidiary', KeyType: 'RANGE' }, ], AttributeDefinitions: [ { AttributeName: 'name', AttributeType: 'S' }, { AttributeName: 'subsidiary', AttributeType: 'S' }, { AttributeName: 'ceo', AttributeType: 'S' }, ], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, LocalSecondaryIndexes: [ { IndexName: 'CeoIndex', KeySchema: [ { AttributeName: 'name', KeyType: 'HASH', }, { AttributeName: 'ceo', KeyType: 'RANGE', }, ], Projection: { ProjectionType: 'ALL', }, }, ], } export const createTable = async params => { try { const data = await ddbClient.send(new CreateTableCommand(params)) console.log('Table created', data) return data } catch (err) { console.log('Error in table creation', err) } } createTable(tableParams1) createTable(tableParams2) createTable(tableParams3) createTable(tableParams4) Create table with V2 SDK var AWS = require('aws-sdk') AWS.config.update({ region: 'eu-north-1', endpoint: 'http://localhost:8000', }) var dynamodb = new AWS.DynamoDB() var params = { TableName: 'Cars', KeySchema: [ { AttributeName: 'id', KeyType: 'HASH' }, //Partition key ], AttributeDefinitions: [{ AttributeName: 'id', AttributeType: 'N' }], ProvisionedThroughput: { ReadCapacityUnits: 5, WriteCapacityUnits: 5, }, } dynamodb.createTable(params, function (err, data) { if (err) { console.error('Unable to create table. Error JSON:', JSON.stringify(err, null, 2)) } else { console.log('Created table. Table description JSON:', JSON.stringify(data, null, 2)) } }) Delete table // deleteTable.js import { DeleteTableCommand } from '@aws-sdk/client-dynamodb' import { ddbClient } from './ddbClient.js' export const deleteTable = async tblName => { try { const data = await ddbClient.send(new DeleteTableCommand({ TableName: tblName })) console.log('Table deleted', data) return data } catch (err) { console.log('Error in table deletion', err) } } deleteTable("Cars") Query table import { QueryCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const queryTable = async () => { const params = { TableName: "Users", ProjectionExpression: "email, age, car, pets", ExpressionAttributeValues: { ":e": "olga.star@gmail.com", }, KeyConditionExpression: "email = :e", } try { const data = await ddbDocClient.send(new QueryCommand(params)) console.log("Success querying: ", data) console.log(JSON.stringify(data.Items)) } catch (err) { console.log("Error", err.stack) } } queryTable() Scan table import { ScanCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const scanTable = async () => { const params = { TableName: "Users", } try { const data = await ddbDocClient.send(new ScanCommand(params)) console.log("Success scanning: ", data) } catch (err) { console.log("Error", err.stack) } } scanTable() Describe table import { DescribeTableCommand } from "@aws-sdk/client-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const describeTable = async () => { const params = { TableName: "Users", } try { const data = await ddbDocClient.send(new DescribeTableCommand(params)) console.log("Success description: ", data) } catch (err) { console.log("Error", err.stack) } } describeTable() With ProjectionExpression Returns only specified attributes. const params = { TableName: "Users", ProjectionExpression: "email, age, car", // show only age & email attributes ExpressionAttributeNames: { "#c": "car" }, ExpressionAttributeValues: { ":a": 35, ":c": "volvo", }, FilterExpression:"#c = :c and age = :a", } With filter TableName: "Users", ProjectionExpression: "email, age, car", // show only age & email attributes ExpressionAttributeValues: { ":a1": 40, ":a2": 45, }, FilterExpression:"age > :a1 and age < :a2", } Filter checking property availability const params = { TableName: "Users", ExpressionAttributeValues: { ":t": true, ":a": 30 }, FilterExpression:"social.instagram = :t and age > :a" , } Filter with CONTAIN const params = { TableName: "Users", ExpressionAttributeValues: { ":g": "jane" }, FilterExpression:"contains(email, :g)" , } Put items import { PutCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" const params1 = { TableName: "Users", Item: { email: "anton.arbus@gmail.com", car: "volvo", age: 35, address: "2nd Avenue, New York", pets: ["cat", "dog", "rat"] }, } const params2 = { TableName: "Users", Item: { email: "jane.blake@gmail.com", car: "audi", age: 21, address: "Boston, unknown street", pets: ["bat"] }, } const params3 = { TableName: "Users", Item: { email: "timo.kuuski@gmail.com", car: "bmw", age: 44, address: "Vaasa, Kaupungintie 45", pets: null, social: { facebook: true, telegram: true, instagram: true } }, } const params4 = { TableName: "Users", Item: { email: "olga.star@gmail.com", car: "mazda", age: 18, address: "Vaasa, Kaupungintie 45", pets: null, social: { facebook: true, telegram: true, instagram: false } }, } export const putItem = async (params) => { try { const data = await ddbDocClient.send(new PutCommand(params)) console.log("Success - item added or updated", data) } catch (err) { console.log("Error", err.stack) } } putItem(params1) putItem(params2) putItem(params3) putItem(params4) Get item import { GetCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const readItem = async () => { const params = { TableName: "Users", Key: { email: "anton.arbus@gmail.com", }, } try { const data = await ddbDocClient.send(new GetCommand(params)) console.log("Success reading: ", data) } catch (err) { console.log("Error", err.stack) } } readItem() Update item import { UpdateCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" const params = { TableName: "Users", Key: { email: "anton.arbus@gmail.com", }, ExpressionAttributeValues: { ":c": "mazda", ":a": 60, }, UpdateExpression: "set car = :c, age = :a", } export const updateItem = async () => { try { const data = await ddbDocClient.send(new UpdateCommand(params)) console.log("Success - item updated", data) } catch (err) { console.log("Error", err.stack) } } updateItem() Delete item import { DeleteCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const deleteItem = async () => { const params = { TableName: "Users", Key: { email: "john.dow@gmail.com", }, } try { const data = await ddbDocClient.send(new DeleteCommand(params)) console.log("Success deleting", data) } catch (err) { console.log("Error", err.stack) } } deleteItem() Get batch items import { BatchGetCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const getBatchItems = async () => { const params = { RequestItems: { // map of TableName to list of Key to get from each table Users: { Keys: [ // a list of primary key value maps { email: 'anton.arbus@gmail.com', }, { email: 'olga.star@gmail.com', }, ], }, }, }; try { const data = await ddbDocClient.send(new BatchGetCommand(params)) console.log("Success reading: ", data) console.log(JSON.stringify(data.Responses)) } catch (err) { console.log("Error", err.stack) } } getBatchItems() Batch write import { BatchWriteCommand } from "@aws-sdk/lib-dynamodb" import { ddbDocClient } from "./ddbDocClient.js" export const writeData = async () => { const TABLE_NAME = "Users" try { for (let i = 0; i < 10; i++) { const params = { RequestItems: { [TABLE_NAME]: [ { PutRequest: { Item: { email: `mail${i}@gmail.com`, age: i, }, }, } ] } } const data = ddbDocClient.send(new BatchWriteCommand(params)) console.log("Success, table updated.") } } catch (error) { console.log("Error", error) } } writeData()