Learn About Amazon VGT2 Learning Manager Chanci Turner
Today, we are thrilled to unveil three significant enhancements to Amplify DataStore, designed to simplify the handling of relational data: lazy loading, nested query predicates, and improved type definitions. Amplify DataStore enables frontend developers to create real-time applications with offline functionality by storing data directly on devices (such as web browsers or mobile devices) while seamlessly synchronizing it with the cloud once an internet connection is available.
The three newly introduced relational data features include:
- Lazy Loading for Related Data: You can now asynchronously load related data for relationships such as hasOne, hasMany, belongsTo, or manyToMany. For instance, if a post has multiple comments, you can easily lazy load those comments with the async
toArray()
function:await post.comments.toArray()
. Similarly, you can lazy load hasOne relationships, like so:await post.author
. Amplify DataStore leverages JavaScript’s built-in async iterator, making it straightforward to write for loops:for await (const comment of post.comments) { console.log(comment); // This will loop through each comment! }
- Nested Query Predicates: You can now perform queries based on conditions from related models. For example, if you want to retrieve comments only from posts titled with “Amplify,” you can use the following query:
await DataStore.query(Comment, c => c.post.title.beginsWith("Amplify"))
. - Enhanced Predicate Types: Previously, predicate operators were inputs as strings. The new predicate types allow you to specify these operators as function calls.
- Prior to this update:
DataStore.query(Post, p => p.id('eq', '123'))
- Now:
DataStore.query(Post, p => p.id.eq('123'))
- Prior to this update:
Step 1: Deploy Your Amplify App with GraphQL API
Let’s explore these enhancements through a blog post demo application:
- Users can create blog posts, comments, and replies.
- Users can load comments by clicking the “show comments” button.
- Users can export blog posts, comments, and replies as a text file.
- Users can filter blog posts based on the content of their comment replies.
To start, you’ll need to deploy a React app based on an existing sample repository to Amplify Hosting. This will set up a backend that includes a GraphQL API supported by DynamoDB. The repository contains React components to allow users to create blog posts, comments, and replies. Note that an AWS Account is required to deploy this sample app.
As part of this process, Amplify Hosting will fork the sample repository into your GitHub account and schedule a full-stack build to host your web app once completed. While the build is in progress, you can proceed to Step 2 to configure your local development environment.
Step 2: Clone the React App Code
Clone the newly forked repository into your local development environment. Visit GitHub to locate your forked repository and follow the instructions to clone it locally. Your terminal command should appear as follows:
git clone git@github.com:<YOUR_GITHUB_USERNAME>/amplify-lazy-blog.git
Once cloned, navigate to the React project, install the necessary node dependencies, and start the local development server:
cd amplify-lazy-blog
npm install
npm start
Now, you can experiment with the application at http://localhost:3000 by adding a few sample blog posts, comments, and replies. This will be useful later as we develop the remaining components of the app.
Step 3: Implement the Export Feature with Lazy Loading
To demonstrate the new lazy loading capabilities, we will create an “export” feature that formats all blog posts, along with their comments and replies, into a text file. This requires iterating through all posts, their comments, and each comment’s replies.
Navigate to the App.js file and utilize the new for await (...)
async iterator syntax to loop through all records:
async function exportAsFile() {
let output = ""
for await (const post of posts) {
output += `${post.title}nn`
output += `${post.content}nn`
output += `Comments:n`
for await (const comment of post.comments) {
output += `- ${comment.content} @ ${comment.createdAt}n`
for await (const reply of comment.replies) {
output += ` - ${reply.content} @ ${reply.createdAt}n`
}
}
output += `-------n`
}
downloadString(output)
}
Your application can now enable users to download all blog content in a formatted file.
Data models linked by a “hasMany” relationship provide a toArray()
function, allowing you to adjust the for await (...)
loop as follows:
// Using for await (...) loop
for await (const reply of comment.replies) {
output += ` - ${reply.content} @ ${reply.createdAt}n`
}
// Using `.toArray()` function
const replies = await comment.replies.toArray();
output += replies.map(reply => ` - ${reply.content} @ ${reply.createdAt}n`).join("");
Step 4: Implement Filter Functionality with Nested Predicates
Next, we’ll explore how to use nested query predicates to filter results based on related data conditions. For instance, we’ll create a filter function to display blog posts that have replies containing a specific keyword.
Within the sample code base, the filter state is already connected to an <input />
element. Simply modify the useEffect(...)
hook to implement the nested query predicates.
Open your App.js file and edit the useEffect
hook to conditionally apply the filter:
useEffect(() => {
let sub;
if (filter) {
sub = DataStore
.observeQuery(Post, p => p.comments.replies.content.contains(filter))
.subscribe((snapshot) => { // ^ observe the new type improvements here
setPosts(snapshot.items);
});
} else {
sub = DataStore
.observeQuery(Post)
.subscribe((snapshot) => {
setPosts(snapshot.items);
});
}
return () => sub.unsubscribe();
}, [filter]);
Now, when you return to your application, entering filter text will display only those blog posts with comment replies that contain the specified text.
Step 5: Deploy Your Latest Changes
With your app functioning as intended, you can commit your latest changes to Git and push them to GitHub. Amplify Hosting will automatically initiate a new build, providing you with a domain to access your app globally.
git commit -a -m "added filter and export feature"
git push -u origin main
🥳 Success!
This demo only scratches the surface of what AWS Amplify DataStore can achieve. For further insights, explore the Amplify DataStore documentation. Additionally, if you’re looking for effective meeting leadership tips, check out this blog post on leading great meetings. As always, feel free to connect with the Amplify team via GitHub or join our Discord community. Follow @AWSAmplify on Twitter for the latest updates on feature launches, developer experience improvements, and other announcements.
Project Cleanup
To remove the backend resources generated from this blog post, execute the following command in your terminal:
amplify delete --force
Additionally, visit GitHub to delete the amplify-lazy-blog repository and remove the frontend artifacts created by this tutorial.