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.
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
PK = STUDENT#123 SK = METADATA GSI_PK = STUDENT#123 GSI_SK = METADATA
PK = COURSE#456 SK = METADATA GSI_PK = COURSE#456 GSI_SK = METADATA
PK = STUDENT#123 SK = COURSE#456 GSI_PK = COURSE#456 GSI_SK = STUDENT#123
PK = COURSE#456 SK = STUDENT#123 GSI_PK = STUDENT#123 GSI_SK = COURSE#456
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';
Query({
IndexName: 'GSI1',
KeyConditionExpression: 'SK = :groupId',
ExpressionAttributeValues: { ':groupId': 'GROUP#123' }
})Query({
IndexName: 'GSI1',
KeyConditionExpression: 'SK = :userId',
ExpressionAttributeValues: { ':userId': 'USER#456' }
})Pass the test and this pattern moves unknown