Bird
Raised Fist0
DynamoDBquery~5 mins

Many-to-many with GSI overloading in DynamoDB

Choose your learning style10 modes available
Introduction
Many-to-many with GSI overloading helps you connect two types of items in one table using a single index, making queries simple and fast without extra tables.
You want to link students and courses they attend in one table.
You need to find all orders for a customer and all customers for a product.
You want to store different relationships in one place and query them easily.
You want to avoid multiple tables and keep your data in one DynamoDB table.
Syntax
DynamoDB
Table with PK and SK attributes
Global Secondary Index (GSI) with GSI_PK and GSI_SK attributes
Store relationship items with overloaded GSI keys
Query GSI with GSI_PK to get related items
GSI overloading means using the same GSI keys for different item types to represent relationships.
PK and SK are primary keys; GSI_PK and GSI_SK are keys for the secondary index.
Examples
An item representing a student with metadata.
DynamoDB
PK = STUDENT#123
SK = METADATA
GSI_PK = STUDENT#123
GSI_SK = METADATA
An item representing a course with metadata.
DynamoDB
PK = COURSE#456
SK = METADATA
GSI_PK = COURSE#456
GSI_SK = METADATA
A relationship item linking student 123 to course 456, overloaded in GSI to query by course.
DynamoDB
PK = STUDENT#123
SK = COURSE#456
GSI_PK = COURSE#456
GSI_SK = STUDENT#123
A relationship item linking course 456 to student 123, overloaded in GSI to query by student.
DynamoDB
PK = COURSE#456
SK = STUDENT#123
GSI_PK = STUDENT#123
GSI_SK = COURSE#456
Sample Program
This example creates a table with a GSI to store students, courses, and their many-to-many relationships. The last query finds all students in course 456 by querying the GSI.
DynamoDB
CREATE TABLE School (
  PK STRING,
  SK STRING,
  GSI_PK STRING,
  GSI_SK STRING,
  Data STRING,
  PRIMARY KEY (PK, SK)
);

-- Create Global Secondary Index
CREATE GLOBAL SECONDARY INDEX GSI1 ON School (GSI_PK, GSI_SK);

-- Insert student
INSERT INTO School VALUES ('STUDENT#123', 'METADATA', 'STUDENT#123', 'METADATA', 'Alice');

-- Insert course
INSERT INTO School VALUES ('COURSE#456', 'METADATA', 'COURSE#456', 'METADATA', 'Math 101');

-- Link student to course (query by course)
INSERT INTO School VALUES ('STUDENT#123', 'COURSE#456', 'COURSE#456', 'STUDENT#123', NULL);

-- Link course to student (query by student)
INSERT INTO School VALUES ('COURSE#456', 'STUDENT#123', 'STUDENT#123', 'COURSE#456', NULL);

-- Query all students in course 456
SELECT PK, SK FROM School WHERE GSI_PK = 'COURSE#456' AND GSI_SK <> 'METADATA';
OutputSuccess
Important Notes
Use clear prefixes like STUDENT# and COURSE# to avoid key collisions.
GSI overloading lets you query relationships from either side easily.
Remember to insert both directions of the relationship for full querying.
Summary
Many-to-many with GSI overloading stores relationships in one table using a special index.
You can query related items from either side by using the GSI keys.
This method avoids extra tables and keeps queries simple and fast.

Practice

(1/5)
1. What is the main advantage of using a Global Secondary Index (GSI) for many-to-many relationships in DynamoDB?
easy
A. It duplicates data across multiple tables for backup.
B. It allows querying related items from both sides without extra tables.
C. It automatically creates foreign key constraints.
D. It enforces strict schema validation on items.

Solution

  1. Step 1: Understand GSI role in many-to-many

    A GSI lets you query items using alternate keys, enabling access from either side of a relationship.
  2. Step 2: Compare with other methods

    Unlike extra tables or joins, GSI overloading stores relationships in one table, simplifying queries.
  3. Final Answer:

    It allows querying related items from both sides without extra tables. -> Option B
  4. Quick Check:

    GSI enables two-way queries without extra tables [OK]
Hint: GSI lets you query both sides in one table [OK]
Common Mistakes:
  • Thinking GSI enforces foreign keys
  • Assuming GSI duplicates data in multiple tables
  • Believing GSI validates schema strictly
2. Which of the following is the correct way to define a GSI for overloading many-to-many relationships in DynamoDB?
easy
A. { "IndexName": "GSI1", "KeySchema": [{"AttributeName": "UserId", "KeyType": "HASH"}], "Projection": {"ProjectionType": "KEYS_ONLY"}}
B. { "IndexName": "GSI1", "KeySchema": [{"AttributeName": "PK", "KeyType": "HASH"}, {"AttributeName": "SK", "KeyType": "RANGE"}], "Projection": {"ProjectionType": "ALL"}}
C. { "IndexName": "GSI1", "KeySchema": [{"AttributeName": "SK", "KeyType": "HASH"}, {"AttributeName": "PK", "KeyType": "RANGE"}], "Projection": {"ProjectionType": "INCLUDE", "NonKeyAttributes": ["Name"]}}
D. { "IndexName": "GSI1", "KeySchema": [{"AttributeName": "ID", "KeyType": "HASH"}], "Projection": {"ProjectionType": "ALL"}}

Solution

  1. Step 1: Identify correct GSI key schema for many-to-many

    The GSI should use SK as HASH and PK as RANGE keys to support querying from both sides.
  2. Step 2: Check projection type

    Projection INCLUDE ensures required attributes like Name are available in the index for queries.
  3. Final Answer:

    Definition with SK as HASH, PK as RANGE, and Projection INCLUDE -> Option C
  4. Quick Check:

    GSI keys SK HASH + PK RANGE + Projection INCLUDE [OK]
Hint: GSI keys: SK as HASH, PK as RANGE, Projection INCLUDE [OK]
Common Mistakes:
  • Using only HASH key without RANGE
  • Swapping PK and SK roles incorrectly
  • Choosing Projection KEYS_ONLY when full data needed
3. Given a DynamoDB table with items storing user-group relationships using GSI overloading, what will this query return?
Query({
  IndexName: 'GSI1',
  KeyConditionExpression: 'SK = :groupId',
  ExpressionAttributeValues: { ':groupId': 'GROUP#123' }
})
medium
A. All users belonging to group with ID 'GROUP#123'.
B. All groups that user 'GROUP#123' belongs to.
C. All items with primary key 'GROUP#123'.
D. An error because PK cannot be used in GSI queries.

Solution

  1. Step 1: Understand GSI key usage in query

    The query uses GSI1 with SK = 'GROUP#123', so it fetches items where GSI partition key (SK attribute) equals this group ID.
  2. Step 2: Interpret the meaning of PK in many-to-many

    SK in GSI represents the group, PK (range) the users, so we get users in that group.
  3. Final Answer:

    All users belonging to group with ID 'GROUP#123'. -> Option A
  4. Quick Check:

    Query by GSI SK = group ID returns users in group [OK]
Hint: GSI SK query with group ID returns users in that group [OK]
Common Mistakes:
  • Confusing group ID with user ID in query
  • Expecting groups for a user instead of users for a group
  • Thinking PK cannot be queried in GSI
4. You wrote this query to get all groups for a user but it returns no results:
Query({
  IndexName: 'GSI1',
  KeyConditionExpression: 'SK = :userId',
  ExpressionAttributeValues: { ':userId': 'USER#456' }
})

What is the likely mistake?
medium
A. The GSI's HASH key is actually SK, not PK, for user queries.
B. The query syntax is invalid; KeyConditionExpression must use SK.
C. ExpressionAttributeValues should use ':user' instead of ':userId'.
D. You must use the main table's primary key, not GSI keys.

Solution

  1. Step 1: Recall GSI key overloading pattern

    In many-to-many GSI overloading, use main table (PK=userId as HASH) for user-to-groups queries, GSI (SK=groupId as HASH) for group-to-users.
  2. Step 2: Check query KeyConditionExpression

    The query uses GSI with SK = userId, but SK holds group IDs, so no results; use main table instead.
  3. Final Answer:

    You must use the main table's primary key, not GSI keys. -> Option D
  4. Quick Check:

    Main table PK=user for user queries [OK]
Hint: Main table for user->groups, GSI for group->users [OK]
Common Mistakes:
  • Using wrong GSI key attribute in query
  • Confusing main table keys with GSI keys
  • Incorrect ExpressionAttributeValues naming
5. You want to store many-to-many relationships between authors and books in one DynamoDB table using GSI overloading. Which design correctly supports querying all books by an author and all authors of a book efficiently?
hard
A. Use PK = 'AUTHOR#<authorId>', SK = 'BOOK#<bookId>' for author-to-book items, and GSI with PK = SK, SK = PK to query from book side.
B. Create separate tables for authors and books, then join them in application code.
C. Use PK = 'BOOK#<bookId>', SK = 'AUTHOR#<authorId>' only, and no GSI.
D. Store all relationships as JSON arrays inside author items without GSI.

Solution

  1. Step 1: Understand many-to-many with GSI overloading

    Store relationships with PK as author and SK as book to query books by author.
  2. Step 2: Use GSI to invert keys for reverse query

    Define GSI with PK = SK and SK = PK to query authors by book efficiently.
  3. Step 3: Evaluate other options

    Separate tables or JSON arrays do not provide efficient two-way queries without extra work.
  4. Final Answer:

    Use PK = 'AUTHOR#<authorId>', SK = 'BOOK#<bookId>' and GSI with PK = SK, SK = PK. -> Option A
  5. Quick Check:

    Overload GSI keys to invert PK and SK for two-way queries [OK]
Hint: Invert PK and SK in GSI for reverse many-to-many queries [OK]
Common Mistakes:
  • Not using GSI for reverse lookup
  • Storing relationships only one way
  • Using separate tables instead of one with GSI
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard