Database

Amazon DynamoDB

Overview

Amazon DynamoDB is a fully managed NoSQL database service provided by AWS. It can store and retrieve any amount of data and serve any level of request traffic, providing serverless, single-digit millisecond performance at any scale.

Details

DynamoDB was announced by Amazon in 2012, developed based on the Dynamo database used internally at Amazon.com. As a fully managed service, it automates server management, patching, software upgrades, replication, and backups, allowing developers to focus on application development.

Key features of DynamoDB:

  • Serverless and fully managed
  • Single-digit millisecond response times
  • Automatic scaling
  • Global tables (multi-region)
  • ACID transactions
  • Fine-grained access control
  • DynamoDB Accelerator (DAX) for in-memory caching
  • DynamoDB Streams for monitoring data changes
  • Encryption (at rest and in transit)
  • Point-in-time recovery

Advantages and Disadvantages

Advantages

  • Serverless: No server management required, reducing operational overhead
  • High performance: Single-digit millisecond latency
  • Auto-scaling: Automatically scales based on traffic
  • High availability: 99.999% SLA guarantee
  • Security: Comprehensive security with encryption and IAM integration
  • AWS integration: Tight integration with other AWS services
  • Cost efficiency: Pay-per-use pricing model

Disadvantages

  • Vendor lock-in: Dependent on AWS architecture
  • SQL limitations: Cannot use SQL queries
  • Data model constraints: Design complexity due to NoSQL constraints
  • Cost: Can become expensive for large-scale usage
  • Learning curve: Need to learn DynamoDB-specific concepts and limitations

Key Links

Code Examples

Setup & Configuration

# AWS CLI installation and configuration
aws configure

# DynamoDB Local (for development)
docker run -p 8000:8000 amazon/dynamodb-local

# AWS SDK installation (Node.js)
npm install aws-sdk

# AWS SDK installation (Python)
pip install boto3

Basic Operations (Table Management)

const AWS = require('aws-sdk')

// DynamoDB client configuration
const dynamodb = new AWS.DynamoDB.DocumentClient({
  region: 'us-east-1'
})

// Create table
const createTableParams = {
  TableName: 'Users',
  KeySchema: [
    { AttributeName: 'userId', KeyType: 'HASH' },  // Partition key
    { AttributeName: 'timestamp', KeyType: 'RANGE' }  // Sort key
  ],
  AttributeDefinitions: [
    { AttributeName: 'userId', AttributeType: 'S' },
    { AttributeName: 'timestamp', AttributeType: 'N' }
  ],
  BillingMode: 'PAY_PER_REQUEST'  // On-demand
}

// List tables
const tables = await dynamodb.listTables().promise()
console.log(tables.TableNames)

Basic Operations (CRUD)

// Create item (Create)
const putParams = {
  TableName: 'Users',
  Item: {
    userId: 'user123',
    timestamp: Date.now(),
    name: 'John Doe',
    email: '[email protected]',
    age: 30,
    address: {
      city: 'New York',
      state: 'NY'
    },
    tags: ['engineer', 'javascript']
  }
}

await dynamodb.put(putParams).promise()

// Read item (Read)
const getParams = {
  TableName: 'Users',
  Key: {
    userId: 'user123',
    timestamp: 1640995200000
  }
}

const result = await dynamodb.get(getParams).promise()
console.log(result.Item)

// Update item (Update)
const updateParams = {
  TableName: 'Users',
  Key: {
    userId: 'user123',
    timestamp: 1640995200000
  },
  UpdateExpression: 'SET age = :age, email = :email',
  ExpressionAttributeValues: {
    ':age': 31,
    ':email': '[email protected]'
  },
  ReturnValues: 'UPDATED_NEW'
}

await dynamodb.update(updateParams).promise()

// Delete item (Delete)
const deleteParams = {
  TableName: 'Users',
  Key: {
    userId: 'user123',
    timestamp: 1640995200000
  }
}

await dynamodb.delete(deleteParams).promise()

Queries and Scans

// Query (search by partition key)
const queryParams = {
  TableName: 'Users',
  KeyConditionExpression: 'userId = :userId',
  ExpressionAttributeValues: {
    ':userId': 'user123'
  },
  ScanIndexForward: false,  // Descending order
  Limit: 10
}

const queryResult = await dynamodb.query(queryParams).promise()
console.log(queryResult.Items)

// Scan (full table search)
const scanParams = {
  TableName: 'Users',
  FilterExpression: 'age > :age',
  ExpressionAttributeValues: {
    ':age': 25
  }
}

const scanResult = await dynamodb.scan(scanParams).promise()
console.log(scanResult.Items)

// Batch get
const batchGetParams = {
  RequestItems: {
    'Users': {
      Keys: [
        { userId: 'user123', timestamp: 1640995200000 },
        { userId: 'user456', timestamp: 1640995300000 }
      ]
    }
  }
}

const batchResult = await dynamodb.batchGet(batchGetParams).promise()

Indexing & Optimization

// Create Global Secondary Index (GSI)
const updateTableParams = {
  TableName: 'Users',
  GlobalSecondaryIndexUpdates: [
    {
      Create: {
        IndexName: 'EmailIndex',
        KeySchema: [
          { AttributeName: 'email', KeyType: 'HASH' }
        ],
        Projection: { ProjectionType: 'ALL' },
        BillingMode: 'PAY_PER_REQUEST'
      }
    }
  ],
  AttributeDefinitions: [
    { AttributeName: 'email', AttributeType: 'S' }
  ]
}

// Query using GSI
const gsiQueryParams = {
  TableName: 'Users',
  IndexName: 'EmailIndex',
  KeyConditionExpression: 'email = :email',
  ExpressionAttributeValues: {
    ':email': '[email protected]'
  }
}

const gsiResult = await dynamodb.query(gsiQueryParams).promise()

Practical Examples

// Transactions
const transactParams = {
  TransactItems: [
    {
      Put: {
        TableName: 'Orders',
        Item: {
          orderId: 'order123',
          userId: 'user123',
          amount: 1000,
          status: 'created'
        }
      }
    },
    {
      Update: {
        TableName: 'Users',
        Key: { userId: 'user123' },
        UpdateExpression: 'ADD totalOrders :inc',
        ExpressionAttributeValues: { ':inc': 1 }
      }
    }
  ]
}

await dynamodb.transactWrite(transactParams).promise()

// Conditional write
const conditionalPutParams = {
  TableName: 'Users',
  Item: {
    userId: 'user789',
    name: 'Jane Smith',
    email: '[email protected]'
  },
  ConditionExpression: 'attribute_not_exists(userId)'
}

// Enable DynamoDB Streams
const enableStreamsParams = {
  TableName: 'Users',
  StreamSpecification: {
    StreamEnabled: true,
    StreamViewType: 'NEW_AND_OLD_IMAGES'
  }
}

Best Practices

// Batch write
const batchWriteParams = {
  RequestItems: {
    'Users': [
      {
        PutRequest: {
          Item: { userId: 'user001', name: 'User 1' }
        }
      },
      {
        DeleteRequest: {
          Key: { userId: 'user002' }
        }
      }
    ]
  }
}

await dynamodb.batchWrite(batchWriteParams).promise()

// Pagination
async function scanAllItems(tableName) {
  let items = []
  let lastEvaluatedKey = null
  
  do {
    const params = {
      TableName: tableName,
      ...(lastEvaluatedKey && { ExclusiveStartKey: lastEvaluatedKey })
    }
    
    const result = await dynamodb.scan(params).promise()
    items = items.concat(result.Items)
    lastEvaluatedKey = result.LastEvaluatedKey
  } while (lastEvaluatedKey)
  
  return items
}

// Error handling
try {
  await dynamodb.put(putParams).promise()
} catch (error) {
  if (error.code === 'ConditionalCheckFailedException') {
    console.log('Conditional check failed')
  } else if (error.code === 'ProvisionedThroughputExceededException') {
    console.log('Throughput limit exceeded')
  }
}

AWS CLI Operations

# Create table
aws dynamodb create-table \
  --table-name Users \
  --attribute-definitions \
    AttributeName=userId,AttributeType=S \
  --key-schema \
    AttributeName=userId,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST

# Put item
aws dynamodb put-item \
  --table-name Users \
  --item '{"userId": {"S": "user123"}, "name": {"S": "John Doe"}}'

# Get item
aws dynamodb get-item \
  --table-name Users \
  --key '{"userId": {"S": "user123"}}'

# List tables
aws dynamodb list-tables