Page updated Jan 16, 2024

Manipulating data

Create and update

To write data to the DataStore, pass an instance of a model to Amplify.DataStore.save():

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> savePost() async {
6 final newPost = Post(
7 title: 'New Post being saved',
8 rating: 15,
9 status: PostStatus.INACTIVE,
10 );
11
12 try {
13 await Amplify.DataStore.save(newPost);
14 } on DataStoreException catch (e) {
15 safePrint('Something went wrong saving model: ${e.message}');
16 }
17}

The save method creates a new record, or in the event that one already exists in the local store, it updates the record.

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> updatePost() async {
6 final oldPost = (await Amplify.DataStore.query(
7 Post.classType,
8 where: Post.ID.eq('123'),
9 ))
10 .first;
11
12 final newPost = oldPost.copyWith(title: 'Updated Title');
13
14 try {
15 await Amplify.DataStore.save(newPost);
16 } on DataStoreException catch (e) {
17 safePrint('Something went wrong updating model: ${e.message}');
18 }
19}

Avoid working with stale data!

Model instances which store values, such as those from the results of a DataStore.Query operation, can become stale and outdated when their properties are updated. This can be the result of a manual change or even a side effect of real time data being received by the application. In order to ensure you are performing mutations on the latest committed state to the system, either perform a query directly before the DataStore.save() operation or observe the model to keep the state updated at all times and perform mutations on that latest state referencing the model instance. The preceding example demonstrates one approach. The following example demonstrates the observeQuery approach.

1class MyApp extends StatefulWidget {
2 const MyApp({Key? key}) : super(key: key);
3
4
5 State<MyApp> createState() => _MyAppState();
6}
7
8class _MyAppState extends State<MyApp> {
9 StreamSubscription<QuerySnapshot<Post>>? _stream;
10
11 // A reference to the retrieved post
12 late Post _post;
13
14
15 void initState() {
16 super.initState();
17 _configure();
18 }
19
20 // Initialize the Amplify libraries and call `observeQuery`
21 Future<void> _configure() async {
22 // ...
23 }
24 ...
25
26 void observeQuery() {
27 _stream = Amplify.DataStore.observeQuery(
28 Post.classType,
29 where: Post.ID.eq('123')
30 ).listen((QuerySnapshot<Post> snapshot) {
31 setState(() {
32 _post = snapshot.items.first;
33 });
34 });
35 }
36
37 Future<void> updatePost(String newTitle) async {
38 final updatedPost = _post.copyWith(title: newTitle);
39 await Amplify.DataStore.save(updatedPost);
40
41 // you do not need to explicitly set _post here; observeQuery will see
42 // the update and set the variable.
43 }
44
45 // Build function and UI elements
46 ...
47
48
49 void dispose() {
50 _stream?.cancel();
51 super.dispose();
52 }
53}

Delete

To delete an item, simply pass in an instance.

Below, you query for an instance with an id of 123, and then delete it, if found:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> deletePostsWithId() async {
6 final postToDelete = (await Amplify.DataStore.query(
7 Post.classType,
8 where: Post.ID.eq('123'),
9 ))
10 .first;
11
12 try {
13 await Amplify.DataStore.delete(postToDelete);
14 } on DataStoreException catch (e) {
15 safePrint('Something went wrong deleting model: ${e.message}');
16 }
17}

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.

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPosts() async {
6 try {
7 final posts = await Amplify.DataStore.query(Post.classType);
8 safePrint('Posts: $posts');
9 } on DataStoreException catch (e) {
10 safePrint('Something went wrong querying posts: ${e.message}');
11 }
12}

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 | beginsWith | between

Numbers: eq | ne | le | lt | ge | gt | between

Lists: contains

For example if you wanted a list of all Post Models that have a rating greater than 4:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPostsWithRatingGreaterThanFour() async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 where: Post.RATING.ge(4),
10 );
11 safePrint('Posts that have a rating > 4: $posts');
12 } on DataStoreException catch (e) {
13 safePrint('Something went wrong querying posts: ${e.message}');
14 }
15}

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:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPublishedPostsWithRatingFour() async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 where: Post.RATING.eq(4).and(Post.STATUS.eq(PostStatus.ACTIVE)),
10 );
11 safePrint('Published posts that have a rating 4: $posts');
12 } on DataStoreException catch (e) {
13 safePrint('Something went wrong querying posts: ${e.message}');
14 }
15}

Alternatively, the or logical operator can also be used:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPublishedOrWithRatingTwoPosts() async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 where: Post.RATING.eq(2).or(Post.STATUS.eq(PostStatus.ACTIVE)),
10 );
11 safePrint('Posts that are published, or have a rating 2: $posts');
12 } on DataStoreException catch (e) {
13 safePrint('Something went wrong querying posts: ${e.message}');
14 }
15}

Sort

Query results can also be sorted by one or more fields.

For example, to sort all Post objects by rating in ascending order:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPostsInAscendingOrderByRating() async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 sortBy: [Post.RATING.ascending()],
10 );
11 safePrint('Posts: $posts');
12 } on DataStoreException catch (e) {
13 safePrint('Something went wrong querying posts: ${e.message}');
14 }
15}

To get all Post objects sorted first by rating in ascending order, and then by title in descending order:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPostsFirstInAscendingRatingOrderThenDescendingTitleOrder() async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 sortBy: [
10 Post.RATING.ascending(),
11 Post.TITLE.descending(),
12 ],
13 );
14 safePrint('Posts: $posts');
15 } on DataStoreException catch (e) {
16 safePrint('Something went wrong querying posts: ${e.message}');
17 }
18}

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:

1import 'package:amplify_flutter/amplify_flutter.dart';
2
3import 'models/ModelProvider.dart';
4
5Future<void> queryPostsWithPagination(int page) async {
6 try {
7 final posts = await Amplify.DataStore.query(
8 Post.classType,
9 pagination: QueryPagination(page: page, limit: 25),
10 );
11 safePrint('Posts: $posts');
12 } on DataStoreException catch (e) {
13 safePrint('Something went wrong querying posts: ${e.message}');
14 }
15}

Query, then observe changes

To both query and observe subsequent changes to a Model, consider using observeQuery.