
DynamoDB in Practice: Steps Three, Four, and Five - Data Access Patterns
Photo by Ricardo Gomez Angel on Unsplash.We’re continuing to work through Jeremy Daly’s 20 “easy” steps to switch from RDBMS to DynamoDB, using Babbl as our example application. In this post we’ll tackle steps three through five - data access patterns.
Step Three
Create a list of ALL your access patterns. If “search” is an access pattern, don’t worry, we’ll deal with that in STEP 17. 😉
As we mentioned previously, we’re building a minimum viable product (MVP), so we want to include only the features required to support that MVP. Let’s think about our app from a user journey perspective.
- CreateUser - The first thing we do is sign up for our app. The heavy lifting here is handled by Amazon Cognito, but ultimately it will return a unique
username
and apreferred_language
. We’ll need to store those. - CreateConversation - Okay, we have a user. The next thing that user wants to do is talk to someone, so we need to create a conversation. This is pretty straightforward: a guid/uuid for the
id
, now as thedate_time_started
, and an empty string for thetitle
. If it’s a two-person conversation, each user will see the other’susername
as the conversation title. If it’s multi-user, we can prompt for a title in a later feature. - CreateParticipation - This happens behind the scenes with
CreateConversation
or when an additional user is added to an existing conversation. Pretty straightforward many to many stuff: the user we’re adding gets herusername
added as theuser_id
, the conversation we’re adding to has itsid
added as theconversation_id
, and we use now as thedate_time_joined
. - CreateMessage - This one is a little more complicated, but nothing too bad. We have two cases:
- User sending a new message: here we use a guid/uuid for the message
id
,null
as theoriginal_message_id
, the user’susername
as thesender_id
, the conversation’sid
as theconversation_id
, and the user’spreferred_language
as thelanguage
. We also need to kick off a background job to translate the messagebody
(We forgot to include this; major oversight!) once into each unique language required by a participant in the conversation - a great use case for AWS Step Functions!. - Translated message: once that background task completes, the returned translation should be added as a new message with a new guid/uuid as the
id
, the original message’sid
as theoriginal_message_id
, the same user’susername
as thesender_id
, the conversation’sid
as theconversation_id
, the translation target language as thelanguage
, and the translated text as thebody
.
- User sending a new message: here we use a guid/uuid for the message
- GetConversationsByUser - Fairly straightforward again. When a user logs in, she should see a list of all conversations she’s participating in sorted by reverse chronological order of the last message received.
- GetUsersByConversation - When you’re sending text, you want to know who’s receiving it. This lists all users participating in a given conversation.
- GetMessagesByConversation - The soul of the app. Get a list of all messages in a particular conversation filtered by the user’s
preferred_language
.
Step Four
Narrow down your access patterns to the ones required by app users. Data analysis and admin tasks, such as analytics, aggregations, behavioral triggers, etc, are all important, but likely not necessary for the end user interacting with your app in real-time. 🚫📊
Well, since we’re targeting an MVP, we need all the ones outlined above. There are some other things we can do later, such as adding read receipts, searching messages, or the ability to delete messages, but for now, we have to keep all of them:
- CreateUser
- CreateConversation
- CreateParticipation
- CreateMessage
- GetConversationsByUser
- GetUsersByConversation
- GetMessagesByConversation
Step Five
Determine if your user access patterns require ad hoc queries that need to reshape the data. Likely the answer is, no. However, if you’re building an OLAP application, NoSQL is not a good choice. Pat yourself on the back for trying, and use another technology. 🤷♂️
No, none of our access patterns require ad hoc queries to reshape the data.
Correcting our ERD
As we saw above, we left out a pretty big feature for a chat app: message bodies! Our message entity should look as follows:
Message
id
- (primary key) a guid/uuid unique to this messageoriginal_message_id
- (foreign key, nullable) theid
of the original message from which this instance was translated, ornull
if this is the original messagesender_id
- (foreign key) theusername
of the user who sent this messageconversation_id
- (foreign key) theid
of the conversation where this message was sentlanguage
- the Amazon Translate language code for this message instancebody
- the message body
And now, our updated ERD looks as follows:
Next up - Rick Houlihan!