How To Model 1-Many Relationships & Reverse Lookups In DynamoDB
Welcome to the 35th edition of Excelling With DynamoDB! (New branding cover image!)
In this week’s issue, I'll discuss how to model two types of common relationships in DynamoDB: the 1-to-many relationship and its reverse lookup.
Modeling relationships in your data is the core of any database design.
This isn't only true with SQL but with DynamoDB as well, especially when you group multiple entities in the same table (using the single table design).
A classical database design pattern is to enable queries for one to many relationships as well as reverse lookup queries.
A reverse lookup query are simply querying the inverse of the one-to-many relationship query.
For example, i can query all courses a given student is enrolled in and then i can do a reverse lookup to find out all students enrolled in a given course.
This is a typical reverse lookup query.
In DynamoDB, we can model both one-to-many relationship queries and their reverse lookup queries by using a global secondary index (GSI).
Let's take a look at how that works.
Modeling one-to-many relationships
Imagine a university database that stores records on courses and students.
The two most typical queries performed against the system are:
For the first query, we can provide a courseID and retrieve the list of student records.
For the second query we can provide a studentID and retreive the list of course records.
Let's attempt to model the first pattern in our DynamoDB base table and the second pattern in a GSI.
Base Table
Each item will be identified by a composite key: the studentID as the partition key and the courseID as the sort key.
Querying a one-to-many relationship
Now i can query all courses a student is taking by providing the studentID.
Here's an example query:
Recommended by LinkedIn
TableName: "courses",
KeyConditionExpression: "#studentID = 'stu#101' AND begins_with(#courseID, 'cs#')
I specify that i want to retrieve all items in the stu#101 item collection (partition), whose courseID (sort key) begins with the sequence "cs#".
Essentially that gives me all courses that student "stu#101" is enrolled in.
Modeling a Reverse Lookup
Now let's model the reverse lookup query.
We need to model the data so that we can get all students enrolled in a given course.
With DynamoDB, this is super simple. We'll just create a GSI and swap the partition and sort keys:
In this GSI, the base table's partition key is now the GSI's sort key and the base table's sort key is now the GSI's partition key; a simple key swap.
Performing the reverse lookup
We can now query this reverse lookup index simply.
We'll provide a courseID and retrieve a list of enrolled students.
Here's an example query:
TableName: "courses",
KeyConditionExpression: "#courseID = 'cs#201' AND begins_with(#studentID, 'stu#')
With virtually no effort we can satisfy both of the most common access patterns for this course system.
Conclusion
In this article, I explain how to model one-to-many relationships and reverse lookups in DynamoDB, particularly for a university database with students and courses.
By using a base table for one-to-many queries (e.g. courses a student is enrolled in) and a global secondary index (GSI) with swapped keys for reverse lookups (e.g. students enrolled in a course), both access patterns can be efficiently satisfied.
👋 My name is Uriel Bitton and I hope you learned something in this edition of Excelling With DynamoDB.
♻️ You can share the article with your network to help others learn as well.
📅 If you're looking for help with DynamoDB, let's have a quick chat:
🙌 I hope to see you in the next week's edition!
Simplifying System Design
1moThis is an interesting take, Uriel Bitton. Many people have the misconception that NoSQL = NoModel