This document contains executable AWS CLI commands to test all query patterns for the GLAD entities table.
Table Structure (from CDK):
- Partition Key (PK):
EntityType(String) - Entity type discriminator - Sort Key (SK):
entity_id(String) - Unique identifier for each entity - Billing Mode: PAY_PER_REQUEST (on-demand)
- Point-in-Time Recovery: Disabled
- Deletion Protection: Enabled
Entity Types:
User- User profilesSkill- Master skill definitions (catalog)UserSkill- User-to-skill relationships with proficiency data
With just ONE Global Secondary Index using composite keys, you can create 15+ different query patterns!
This is the power of DynamoDB's multi-key GSI design. Instead of creating multiple indexes for different query patterns, you strategically design a single index with composite keys that enables flexible querying at multiple levels of granularity.
Composite Partition Key (1 attribute):
Category(String) - Skill category for broad partitioning
Composite Sort Keys (4 attributes):
SkillName(String) - Specific skill nameProficiencyLevel(String) - Skill proficiency levelYearsOfExperience(Number) - Years of experience with the skillUsername(String) - User identifier (ensures uniqueness)
Why This Design is Powerful:
✅ Hierarchical Querying: Query from broad (Category) to specific (down to individual Username)
✅ Partial Sort Keys: Use just SK1, or SK1+SK2, or SK1+SK2+SK3, etc. - DynamoDB allows left-to-right querying
✅ Range Operations: Apply >=, <=, BETWEEN on the last sort key in your query
✅ Efficient Sorting: Data is automatically sorted by the composite key order
✅ Single Index Cost: Pay for only one GSI instead of multiple indexes
Query Flexibility Examples:
- Query 1:
Category = "Programming"→ All programming skills - Query 2:
Category = "Programming" AND SkillName = "Python"→ All Python users - Query 3:
Category = "Programming" AND SkillName = "Python" AND ProficiencyLevel = "Expert"→ Python experts - Query 4:
... AND YearsOfExperience >= 5→ Experienced Python experts - Query 5:
... AND Username = "john"→ Specific user check
All from ONE index!
| EntityType | entity_id | Additional Attributes | Description |
|---|---|---|---|
User |
USER#john_doe |
Username, Name, Email, CreatedAt, UpdatedAt | User profile |
Skill |
SKILL#python |
SkillID, SkillName, Category, Description, Tags | Master skill catalog |
UserSkill |
USERSKILL#john_doe#python |
Username, SkillID, SkillName, Category, ProficiencyLevel, YearsOfExperience, Endorsements, LastUsedDate | User's skill with proficiency |
Here's how UserSkill items appear in the GSI (sorted by composite sort key):
| Category | SkillName | ProficiencyLevel | YearsOfExperience | Username | Endorsements | LastUsedDate |
|---|---|---|---|---|---|---|
| Programming | Python | Beginner | 1 | jane_smith | 5 | 2025-12-10 |
| Programming | Python | Intermediate | 3 | mike_wilson | 25 | 2025-11-15 |
| Programming | Python | Advanced | 5 | alice_johnson | 65 | 2025-12-15 |
| Programming | Python | Expert | 7 | bob_smith | 120 | 2025-12-18 |
| Programming | Python | Expert | 10 | diana_evans | 200 | 2025-12-20 |
| Frontend | TypeScript | Advanced | 4 | alex_chen | 30 | 2025-12-15 |
| Frontend | TypeScript | Expert | 6 | betty_wang | 75 | 2025-12-18 |
| Backend | Go | Expert | 7 | alice_smith | 80 | 2025-12-18 |
| Cloud | AWS | Expert | 9 | charlie_brown | 150 | 2025-11-20 |
| DevOps | Docker | Beginner | 1 | tom_davis | 8 | 2025-10-10 |
Notice: Items are naturally sorted by Category → SkillName → ProficiencyLevel → YearsOfExperience → Username. This sorting enables efficient range queries and pagination.
- EntityType: Discriminator to separate Users, Skills, and UserSkills
- entity_id: Hierarchical identifier pattern:
USER#<username>SKILL#<skill_id>USERSKILL#<username>#<skill_id>
- Category (PK): Broad partitioning (Programming, Frontend, Backend, Cloud, DevOps, Database, Mobile, Data, Security, Other)
- SkillName (SK1): Specific skill within category
- ProficiencyLevel (SK2): Beginner, Intermediate, Advanced, Expert
- YearsOfExperience (SK3): NUMBER type for range queries and sorting
- Username (SK4): User identifier, ensures uniqueness
- Endorsements: NUMBER - Peer endorsements count
- LastUsedDate: STRING (ISO 8601) - When skill was last used
- Notes: STRING - Additional skill notes
- SkillID: STRING - Immutable skill identifier
- CreatedAt/UpdatedAt: STRING (ISO 8601) - Timestamps
Index Name: BySkill
Partition Key (1 attribute):
Category(String)
Sort Keys (4 attributes):
SkillName(String)ProficiencyLevel(String)YearsOfExperience(Number)Username(String)
Note: Endorsements (Number) and LastUsedDate (String) are not in the GSI keys, but can be used with FilterExpression.
| # | Pattern Name | Table/Index | Key Condition | Use Case | API Endpoint |
|---|---|---|---|---|---|
| 1 | Get All Users | Main Table | EntityType = "User" |
List all users in system | GET /users |
| 2 | Get All Master Skills | Main Table | EntityType = "Skill" |
List all master skill definitions | GET /master-skills |
| 3 | Get All User Skills | Main Table | EntityType = "UserSkill" |
List all user skill records | - |
| 4 | Get Specific User | Main Table | EntityType = "User" AND entity_id = "USER#<username>" |
Get user profile by username | GET /users/{username} |
| 5 | Get Specific Master Skill | Main Table | EntityType = "Skill" AND entity_id = "SKILL#<skillID>" |
Get master skill details | GET /master-skills/{skillID} |
| 6 | Get Specific User Skill | Main Table | EntityType = "UserSkill" AND entity_id = "USERSKILL#<username>#<skillID>" |
Get user's specific skill | GET /users/{username}/skills/{skillName} |
| 7 | Get All Skills for User | Main Table | EntityType = "UserSkill" AND begins_with(entity_id, "USERSKILL#<username>#") |
List all skills for a user | GET /users/{username}/skills |
| # | Pattern Name | PK | SK Condition | Filter | Use Case | API Endpoint |
|---|---|---|---|---|---|---|
| 8 | All Skills in Category | Category = :cat |
- | - | All skills in Programming category | GET /skills?category=Programming |
| 9 | All Users with Skill | Category = :cat |
SkillName = :skill |
- | Everyone who knows Python | GET /skills/python/users |
| 10 | Users at Skill Level | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
- | All Python experts | GET /skills/python/users?level=Expert |
| 11 | Users with Min Experience | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level AND YearsOfExperience >= :years |
- | Python experts with 5+ years | GET /skills/python/users?level=Expert&minYears=5 |
| 12 | Users by Experience (Desc) | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
--scan-index-forward false |
Most experienced Python experts | GET /skills/python/users?level=Expert&sort=experience_desc |
| 13 | Experience Range | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level AND YearsOfExperience BETWEEN :min AND :max |
- | Intermediate Python devs (2-5 years) | GET /skills/python/users?level=Intermediate&minYears=2&maxYears=5 |
| 14 | Check User Skill Level | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level AND Username = :user |
- | Check if john_doe is Python expert | GET /users/john_doe/skills/python?checkLevel=Expert |
| 15 | Filter by Endorsements | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
Endorsements >= :min |
Python experts with 50+ endorsements | GET /skills/python/users?level=Expert&minEndorsements=50 |
| 16 | Filter by Last Used | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
LastUsedDate >= :date |
Python experts active in last 6 months | GET /skills/python/users?level=Expert&activeSince=2024-06-20 |
| 17 | Multi-Criteria Filter | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level AND YearsOfExperience >= :years |
Endorsements >= :min AND LastUsedDate >= :date |
Senior Python experts (5+ years, 50+ endorsements, recently active) | GET /skills/python/users?level=Expert&minYears=5&minEndorsements=50&activeSince=2024-06-20 |
| 18 | All Expert Skills in Category | Category = :cat |
- | ProficiencyLevel = :level |
All expert-level skills in Programming | GET /skills?category=Programming&level=Expert |
| 19 | Skills with Prefix | Category = :cat |
begins_with(SkillName, :prefix) |
- | All Java-related skills (Java, JavaScript) | GET /skills?category=Programming&skillPrefix=Java |
| 20 | Proficiency Distribution | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
--select COUNT |
Count Python users by proficiency level | GET /skills/python/distribution |
| 21 | Top N by Experience | Category = :cat |
SkillName = :skill AND ProficiencyLevel = :level |
--scan-index-forward false --limit N |
Top 10 most experienced Go experts | GET /skills/go/users/top?limit=10&level=Expert |
| 22 | Users Above Min Level | Category = :cat |
SkillName = :skill |
ProficiencyLevel IN (:level1, :level2) |
TypeScript users at Advanced or Expert | GET /skills/typescript/users?minLevel=Advanced |
| 23 | Pagination | Category = :cat |
- | --limit N --exclusive-start-key |
Paginated results for category | GET /skills?category=Programming&page=2&limit=20 |
Total Access Patterns: 23 (7 Main Table + 16 GSI)
# AWS Profile
export AWS_PROFILE={YOUR_AWS_PROFILE_NAME}
# Table and Index names
TABLE_NAME="glad-entities"
GSI_NAME="BySkill"aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType" \
--expression-attribute-values '{
":entityType": {"S": "User"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType" \
--expression-attribute-values '{
":entityType": {"S": "Skill"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType" \
--expression-attribute-values '{
":entityType": {"S": "UserSkill"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType AND entity_id = :entityId" \
--expression-attribute-values '{
":entityType": {"S": "User"},
":entityId": {"S": "USER#john_doe"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType AND entity_id = :entityId" \
--expression-attribute-values '{
":entityType": {"S": "Skill"},
":entityId": {"S": "SKILL#python"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType AND entity_id = :entityId" \
--expression-attribute-values '{
":entityType": {"S": "UserSkill"},
":entityId": {"S": "USERSKILL#jane_doe#python"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType AND begins_with(entity_id, :prefix)" \
--expression-attribute-values '{
":entityType": {"S": "UserSkill"},
":prefix": {"S": "USERSKILL#john_doe#"}
}'Use Case: List all user skills in a specific category (e.g., all Programming skills)
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category" \
--expression-attribute-values '{
":category": {"S": "Programming"}
}'Returns: All UserSkill items in the Programming category
Use Case: Find everyone who has Python, regardless of proficiency level
//todo
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName" \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "JavaScript"}
}'Returns: All UserSkill items for Python (all proficiency levels)
Use Case: Find all Python experts
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"}
}'Returns: All Python experts
Use Case: Find Python experts with at least 5 years of experience
Option A: Using Sort Key Condition (Efficient)
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level AND YearsOfExperience >= :minYears" \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"},
":minYears": {"N": "1"}
}'Returns: Python experts with 5+ years of experience, sorted by experience (ascending)
Use Case: Find Python experts ordered by most experienced first
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--no-scan-index-forward \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"}
}'Returns: Python experts sorted by experience (most experienced first)
Use Case: Find intermediate Python developers with 2-5 years of experience
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level AND YearsOfExperience BETWEEN :minYears AND :maxYears" \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"},
":minYears": {"N": "1"},
":maxYears": {"N": "10"}
}'Returns: Intermediate Python developers with 2-5 years experience
Use Case: Check if user "john_doe" is a Python expert
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType AND entity_id = :entityId" \
--expression-attribute-values '{
":entityType": {"S": "UserSkill"},
":entityId": {"S": "USERSKILL#jane_doe#python"}
}'
Returns: Single UserSkill item if exists, empty if not
Use Case: Find Python experts with at least 50 endorsements
Note: Endorsements is NOT in the GSI keys, so we use FilterExpression
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--filter-expression "Endorsements >= :minEndorsements" \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"},
":minEndorsements": {"N": "2"}
}'Returns: Python experts with 50+ endorsements (filtered after query)
Use Case: Find Beginners who used Docker in the last 6 months
Note: LastUsedDate is NOT in the GSI keys, so we use FilterExpression
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--filter-expression "LastUsedDate >= :recentDate" \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"},
":recentDate": {"S": "2024-06-20"}
}'Returns: Beginners who used Docker since 2024-06-20
Use Case: Find senior Python experts (5+ years, 50+ endorsements, used recently)
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level AND YearsOfExperience >= :minYears" \
--filter-expression "Endorsements >= :minEndorsements AND LastUsedDate >= :minDate" \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "Python 3"},
":level": {"S": "Expert"},
":minYears": {"N": "5"},
":minEndorsements": {"N": "50"},
":minDate": {"S": "2024-06-20"}
}'Returns: Highly qualified, active Python experts
Use Case: Find all Expert-level skills in Programming category
ProficiencyLevel is a GSI key attribute (SK2) and cannot be used in FilterExpression.
Error: Filter Expression can only contain non-primary key attributes: Primary key attribute: ProficiencyLevel
Workaround: Query each proficiency level separately or fetch all skills in the category and filter in application code.
# This query will return an ERROR - kept for reference
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category" \
--filter-expression "ProficiencyLevel = :level" \
--expression-attribute-values '{
":category": {"S": "Programming"},
":level": {"S": "Expert"}
}'Alternative - Fetch all and filter in code:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category" \
--expression-attribute-values '{
":category": {"S": "Programming"}
}'
# Then filter ProficiencyLevel = "Expert" in your application codeUse Case: Find all users with skills starting with "Java" (Java, JavaScript, etc.)
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND begins_with(SkillName, :skillPrefix)" \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillPrefix": {"S": "Java"}
}'Returns: All UserSkills with skills starting with "Java"
Use Case: Get count of Python users at each proficiency level
Query 1 - Beginner:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--select COUNT \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "Python"},
":level": {"S": "Beginner"}
}'Query 2 - Intermediate:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--select COUNT \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "Python"},
":level": {"S": "Intermediate"}
}'Query 3 - Advanced:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--select COUNT \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "Python"},
":level": {"S": "Advanced"}
}'Query 4 - Expert:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--select COUNT \
--expression-attribute-values '{
":category": {"S": "DevOps"},
":skillName": {"S": "Docker"},
":level": {"S": "Beginner"}
}'Returns: Count for each proficiency level (4 queries total)
Use Case: Get top 10 most experienced Go experts
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--limit 10 \
--expression-attribute-values '{
":category": {"S": "Backend"},
":skillName": {"S": "Go"},
":level": {"S": "Expert"}
}'Returns: Top 10 Go experts by experience
Use Case: Find TypeScript users at Advanced OR Expert level
Note: This pattern returns ALL proficiency levels, so filter in application code or run separate queries for each level.
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName" \
--expression-attribute-values '{
":category": {"S": "Frontend"},
":skillName": {"S": "TypeScript"}
}'
# Then filter for ProficiencyLevel IN ("Advanced", "Expert") in application codeAlternative - Run two separate queries:
# Query 1: Advanced
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--expression-attribute-values '{
":category": {"S": "Frontend"},
":skillName": {"S": "TypeScript"},
":level": {"S": "Advanced"}
}'
# Query 2: Expert
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName AND ProficiencyLevel = :level" \
--expression-attribute-values '{
":category": {"S": "Frontend"},
":skillName": {"S": "TypeScript"},
":level": {"S": "Expert"}
}'
# Merge results in application codeReturns: TypeScript users at Advanced or Expert level
Use Case: Get first 20 skills in Programming category, then get next page
Page 1:
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category" \
--limit 20 \
--expression-attribute-values '{
":category": {"S": "Programming"}
}'Page 2 (use LastEvaluatedKey from previous response):
aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category" \
--limit 20 \
--exclusive-start-key '{"Category":{"S":"Programming"},"SkillName":{"S":"Python"},"ProficiencyLevel":{"S":"Expert"},"YearsOfExperience":{"N":"5"},"Username":{"S":"alice"},"EntityType":{"S":"UserSkill"},"entity_id":{"S":"USERSKILL#alice#python"}}' \
--expression-attribute-values '{
":category": {"S": "Programming"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--key-condition-expression "EntityType = :entityType" \
--select COUNT \
--expression-attribute-values '{
":entityType": {"S": "User"}
}'aws dynamodb query \
--table-name glad-entities --profile AWS_PROFILE \
--index-name BySkill \
--key-condition-expression "Category = :category AND SkillName = :skillName" \
--select COUNT \
--expression-attribute-values '{
":category": {"S": "Programming"},
":skillName": {"S": "Python"}
}'aws dynamodb get-item \
--table-name glad-entities --profile AWS_PROFILE \
--key '{
"EntityType": {"S": "User"},
"entity_id": {"S": "USER#john_doe"}
}'aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "User"},
"entity_id": {"S": "USER#john_doe"},
"Username": {"S": "john_doe"},
"Name": {"S": "John Doe"},
"Email": {"S": "john@example.com"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "User"},
"entity_id": {"S": "USER#jane_doe"},
"Username": {"S": "jane_doe"},
"Name": {"S": "Jane Doe"},
"Email": {"S": "jane@example.com"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "User"},
"entity_id": {"S": "USER#alice_smith"},
"Username": {"S": "alice_smith"},
"Name": {"S": "Alice Smith"},
"Email": {"S": "alice@example.com"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "Skill"},
"entity_id": {"S": "SKILL#python"},
"SkillID": {"S": "python"},
"SkillName": {"S": "Python"},
"Category": {"S": "Programming"},
"Description": {"S": "Python programming language"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "Skill"},
"entity_id": {"S": "SKILL#go"},
"SkillID": {"S": "go"},
"SkillName": {"S": "Go"},
"Category": {"S": "Backend"},
"Description": {"S": "Go programming language"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "Skill"},
"entity_id": {"S": "SKILL#react"},
"SkillID": {"S": "react"},
"SkillName": {"S": "React"},
"Category": {"S": "Frontend"},
"Description": {"S": "React JavaScript library"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-01-01T00:00:00Z"}
}'# John - Python Expert (10 years, 150 endorsements)
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "UserSkill"},
"entity_id": {"S": "USERSKILL#john_doe#python"},
"Username": {"S": "john_doe"},
"SkillID": {"S": "python"},
"SkillName": {"S": "Python"},
"Category": {"S": "Programming"},
"ProficiencyLevel": {"S": "Expert"},
"YearsOfExperience": {"N": "10"},
"Endorsements": {"N": "150"},
"LastUsedDate": {"S": "2025-12-15"},
"Notes": {"S": "Experienced Python developer"},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-12-15T00:00:00Z"}
}'
# Jane - Python Advanced (5 years, 42 endorsements)
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "UserSkill"},
"entity_id": {"S": "USERSKILL#jane_doe#python"},
"Username": {"S": "jane_doe"},
"SkillID": {"S": "python"},
"SkillName": {"S": "Python"},
"Category": {"S": "Programming"},
"ProficiencyLevel": {"S": "Advanced"},
"YearsOfExperience": {"N": "5"},
"Endorsements": {"N": "42"},
"LastUsedDate": {"S": "2025-11-20"},
"Notes": {"S": ""},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-11-20T00:00:00Z"}
}'
# Alice - Go Expert (7 years, 80 endorsements)
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "UserSkill"},
"entity_id": {"S": "USERSKILL#alice_smith#go"},
"Username": {"S": "alice_smith"},
"SkillID": {"S": "go"},
"SkillName": {"S": "Go"},
"Category": {"S": "Backend"},
"ProficiencyLevel": {"S": "Expert"},
"YearsOfExperience": {"N": "7"},
"Endorsements": {"N": "80"},
"LastUsedDate": {"S": "2025-12-18"},
"Notes": {"S": ""},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-12-18T00:00:00Z"}
}'
# John - React Intermediate (3 years, 25 endorsements)
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "UserSkill"},
"entity_id": {"S": "USERSKILL#john_doe#react"},
"Username": {"S": "john_doe"},
"SkillID": {"S": "react"},
"SkillName": {"S": "React"},
"Category": {"S": "Frontend"},
"ProficiencyLevel": {"S": "Intermediate"},
"YearsOfExperience": {"N": "3"},
"Endorsements": {"N": "25"},
"LastUsedDate": {"S": "2025-12-10"},
"Notes": {"S": ""},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-12-10T00:00:00Z"}
}'
# Jane - Python Beginner (1 year, 5 endorsements)
aws dynamodb put-item \
--table-name glad-entities --profile AWS_PROFILE \
--item '{
"EntityType": {"S": "UserSkill"},
"entity_id": {"S": "USERSKILL#jane_doe#go"},
"Username": {"S": "jane_doe"},
"SkillID": {"S": "go"},
"SkillName": {"S": "Go"},
"Category": {"S": "Backend"},
"ProficiencyLevel": {"S": "Beginner"},
"YearsOfExperience": {"N": "1"},
"Endorsements": {"N": "5"},
"LastUsedDate": {"S": "2025-10-15"},
"Notes": {"S": ""},
"CreatedAt": {"S": "2025-01-01T00:00:00Z"},
"UpdatedAt": {"S": "2025-10-15T00:00:00Z"}
}'aws dynamodb describe-table \
--table-name glad-entities --profile AWS_PROFILE \
--query "Table.GlobalSecondaryIndexes[?IndexName=='BySkill']"aws dynamodb describe-table \
--table-name glad-entities --profile AWS_PROFILE \
--query "Table.GlobalSecondaryIndexes[?IndexName=='BySkill'].IndexStatus"aws dynamodb describe-table \
--table-name glad-entities --profile AWS_PROFILE \
--query "Table.AttributeDefinitions"aws dynamodb scan \
--table-name glad-entities --profile AWS_PROFILE \
--limit 10| Pattern | PK | SK1 | SK2 | SK3 | SK4 | Use Case |
|---|---|---|---|---|---|---|
| 1 | Category | - | - | - | - | All skills in category |
| 2 | Category | SkillName | - | - | - | All users with skill |
| 3 | Category | SkillName | ProficiencyLevel | - | - | Users at skill level |
| 4 | Category | SkillName | ProficiencyLevel | YearsOfExperience >= | - | Min experience filter |
| 5 | Category | SkillName | ProficiencyLevel | YearsOfExperience (desc) | - | Most experienced first |
| 6 | Category | SkillName | ProficiencyLevel | YearsOfExperience BETWEEN | - | Experience range |
| 7 | Category | SkillName | ProficiencyLevel | YearsOfExperience | Username | Specific user check |
-
Data Types:
YearsOfExperience: NUMBER type (e.g., {"N": "5"})Endorsements: NUMBER type (e.g., {"N": "42"})- No zero-padding needed since both are stored as numbers
-
Sort Key Hierarchy:
- Must query from left to right
- Can use partial sort keys (SK1, SK1+SK2, SK1+SK2+SK3, etc.)
- Cannot skip sort keys (e.g., cannot query SK1+SK3 without SK2)
-
Range Queries:
- Only on the LAST sort key specified
- Operators:
<,>,<=,>=,BETWEEN,begins_with
-
FilterExpression:
- For attributes NOT in GSI keys (Endorsements, LastUsedDate)
- Applied AFTER query (less efficient than KeyConditionExpression)
-
Sorting:
- Default: Ascending (
--scan-index-forward true) - Descending:
--scan-index-forward false
- Default: Ascending (
-
Pagination:
- Use
--limitto control page size - Use
--exclusive-start-keywith LastEvaluatedKey for next page
- Use