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()