Manipulating data
Getting started
To get started, first import the DataStore
API:
import { DataStore } from 'aws-amplify/datastore';
Create and update
To write data to the DataStore, pass an instance of a model to Amplify.DataStore.save()
:
await DataStore.save( new Post({ title: 'My First Post', rating: 10, status: PostStatus.INACTIVE }));
The save
method creates a new record, or in the event that one already exists in the local store, it updates the record.
async function updatePost(id, newTitle) { const original = await DataStore.query(Post, id);
if (original) { const updatedPost = await DataStore.save( Post.copyOf(original, updated => { updated.title = newTitle }) ); }}
async function updatePost(id, newTitle) { const original = await DataStore.query(Post, id); const updatedPost = await DataStore.save( Post.copyOf(original, updated => { updated.title = newTitle }) );}
// Example showing how to observe the model and keep state updated before// performing a save. This uses the useEffect React hook, but you can// substitute for a similar mechanism in your application lifecycle with// other frameworks.
function App() { const [post, setPost] = useState();
useEffect(() => { /** * This keeps `post` fresh. */ const sub = DataStore.observeQuery(Post, (c) => c.id.eq('e4dd1dc5-e85c-4566-8aaa-54a801396456') ).subscribe(({ items }) => { setPost(items[0]); });
return () => { sub.unsubscribe(); }; }, []);
/** * Create a new Post */ async function onCreate() { const post = await DataStore.save( new Post({ title: `New title ${Date.now()}`, rating: Math.floor(Math.random() * (8 - 1) + 1), status: PostStatus.ACTIVE }) ); setPost(post); }
return ( <> <h1>{post?.title}</h1> <input type="button" value="NEW POST" onClick={onCreate} /> <input disabled={!post} type="text" value={post?.title ?? ''} onChange={({ target: { value } }) => { /** * Each keypress updates the post in local React state. */ setPost( Post.copyOf(post, (draft) => { draft.title = value; }) ); }} /> <input disabled={!post} type="button" value="Save" onClick={async () => { /** * This post is already up-to-date because `observeQuery` updated it. */ if (!post) return; await DataStore.save(post); console.log('Post saved'); }} /> </> );}
Delete
To delete an item, simply pass in an instance.
const toDelete = await DataStore.query(Post, '1234567');if (toDelete) { DataStore.delete(toDelete);}
const toDelete = await DataStore.query(Post, '1234567');DataStore.delete(toDelete);
You can also pass predicate operators to delete multiple items. For example, the following will delete all draft posts:
await DataStore.delete(Post, (post) => post.status.eq(PostStatus.INACTIVE));
Additionally, you can perform a conditional delete. For instance, only delete if a post is in draft status by passing in an instance of a model:
const toDelete = await DataStore.query(Post, '123');if (toDelete) { DataStore.delete(toDelete, (post) => post.status.eq(PostStatus.INACTIVE));}
const todelete = await DataStore.query(Post, '123');DataStore.delete(todelete, (post) => post.status.eq(PostStatus.INACTIVE));
Also, to delete all items for a model you can use Predicates.ALL
:
await DataStore.delete(Post, Predicates.ALL);
Query Data
Queries are performed against the local store. When cloud synchronization is enabled, the local store is updated in the background by the DataStore Sync Engine.
For more advanced filtering, such as matching arbitrary field values on an object, you can supply a query predicate.
Querying for all items
To query for all items, pass in the model name as the argument.
const posts = await DataStore.query(Post);
Querying for a single item
To query for a single item, pass in the ID of the item as the second argument to the query.
const post = await DataStore.query(Post, "1234567");
Predicates
Predicates are filters that can be used to match items in the DataStore. When applied to a query(), they constrain the returned results. When applied to a save(), they act as a pre-requisite for updating the data. You can match against fields in your schema by using the following predicates:
Strings: eq | ne | le | lt | ge | gt | contains | notContains | beginsWith | between
Numbers: eq | ne | le | lt | ge | gt | between
Lists: contains | notContains
For example if you wanted a list of all Post
Models that have a rating
greater than 4:
const posts = await DataStore.query(Post, (c) => c.rating.gt(4));
Multiple conditions can also be used, like the ones defined in GraphQL Transform condition statements. For example, fetch all posts that have a rating greater than 4
and are ACTIVE
:
When using multiple conditions, you can wrap the predicates with the and
operator. For example with multiple conditions:
const posts = await DataStore.query(Post, (c) => c.and(c => [ c.rating.gt(4), c.status.eq(PostStatus.ACTIVE)]));
Alternatively, the or
logical operator can also be used:
If you wanted this to be an or
statement you would wrap your combined predicates with c => c.or(...)
const posts = await DataStore.query(Post, (c) => c.or(c => [ c.rating.gt(4), c.status.eq(PostStatus.ACTIVE) ]));
Sort
Query results can also be sorted by one or more fields.
For example, to sort all Post
objects by rating
in ascending order:
const posts = await DataStore.query(Post, Predicates.ALL, { sort: (s) => s.rating(SortDirection.ASCENDING)});
To get all Post
objects sorted first by rating
in ascending order, and then by title
in descending order:
const posts = await DataStore.query(Post, Predicates.ALL, { sort: (s) => s.rating(SortDirection.ASCENDING).title(SortDirection.DESCENDING)});
Pagination
Query results can also be paginated by passing in a page
number (starting at 0) and an optional limit
(defaults to 100). This will return a list of the first 100 items:
const posts = await DataStore.query(Post, Predicates.ALL, { page: 0, limit: 100});