## Selectively syncing a subset of your data
By default, DataStore fetches all the records that you’re authorized to access from your cloud data source to your local device.
The maximum number of records that will be stored locally is configurable [here](/lib/datastore/conflict).
You can utilize selective sync to persist a subset of your data instead.
Selective sync works by applying predicates to the base and delta sync queries, as well as to incoming subscriptions.
Note that selective sync is applied on top of authorization rules you’ve defined on your schema with the `@auth` directive.
For more information see the [Setup authorization rules](/lib/datastore/setup-auth-rules/) section.
```dart
void _configureAmplify() async {
// Update AmplifyDataStore instance like below
final datastorePlugin = AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(Post.classType, () => Post.RATING.gt(5)),
DataStoreSyncExpression(
Comment.classType,
() => Comment.POST.beginsWith('This'),
)
],
);
...
}
```
When DataStore starts syncing, only Posts with `rating > 5` and Comments with `POST` id begins with `"This"` will be synced down to the user's local store.
Developers should only specify a single `syncExpression` per model. Any subsequent expressions for the same model will
be ignored.
### Reevaluate expressions at runtime
Sync expressions get evaluated whenever DataStore starts.
In order to have your expressions reevaluated, you can execute `Amplify.DataStore.clear()` or `Amplify.DataStore.stop()` followed by `Amplify.DataStore.start()`.
If you have the following expression and you want to change the filter that gets applied at runtime, you can do the following:
```dart
int rating = 5;
Future initialize() async {
final dataStorePlugin = AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(
Post.classType,
() => Post.RATING.gt(rating),
),
],
);
await Amplify.addPlugin(dataStorePlugin);
}
Future changeSync() async {
rating = 1;
try {
await Amplify.DataStore.stop();
} catch(error) {
print('Error stopping DataStore: $error');
}
try {
await Amplify.DataStore.start();
} on Exception catch (error) {
print('Error starting DataStore: $error');
}
}
```
Each time DataStore starts (via `start` or any other operation: `query`, `save`, `delete`, or `observe`), DataStore will reevaluate the `syncExpressions`.
In the above case, the predicate will contain the value `1`, so all Posts with `rating > 1` will get synced down.
Keep in mind: `Amplify.DataStore.stop()` will retain the local store's existing content. Run `Amplify.DataStore.clear()` to clear the locally-stored contents.
When applying a more restrictive filter, clear the local records first by running `DataStore.clear()` instead:
```dart
Future changeSync() async {
rating = 8;
try {
await Amplify.DataStore.clear();
} on Exception catch (error) {
print('Error clearing DataStore: $error');
}
try {
await Amplify.DataStore.start();
} on Exception catch (error) {
print('Error starting DataStore: $error');
}
}
```
This will clear the contents of your local store, reevaluate your sync expressions and re-sync the data from the cloud, applying all of the specified predicates to the sync queries.
You can also have your sync expression return `QueryPredicateConstant.all` in order to remove any filtering for that model. This will have the same effect as the default sync behavior.
```dart
int rating = 5;
Future initialize() async {
var dataStorePlugin = AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(
Post.classType,
() {
if (rating > 0) {
return QueryPredicate.all;
}
return Post.RATING.gt(rating);
},
),
],
);
await Amplify.addPlugin(dataStorePlugin);
}
```
`DataStore.configure()` should only by called once.
### Advanced use case - Query instead of Scan
By default, Datastore sync performs a [Scan](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html) on DynamoDB tables, which is [less efficient](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html) when a table contains a large set of data. You can use `syncExpression` when configuring Datastore to filter synced data to improve performance using [Query](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html) rather than Scan.
You can enable Query during the sync by following the below steps:
1. Create a [Global Secondary Index (GSI)](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html) for your schema, e.g. in the below schema a GSI will be created using field `lastName` as the GSI primary key, and `createdAt` as the GSI sort key. Learn about creating GSIs with the `@index` directive [here](https://docs.amplify.aws/cli/graphql/data-modeling).
```graphql
type User @model {
id: ID!
firstName: String!
lastName: String! @index(name: "byLastName", sortKeyFields: ["createdAt"])
createdAt: AWSDateTime!
}
```
2. Configure DataStore with `syncExpression` returning a predicate that maps to a query expression.
To construct a query expression, return a predicate with the primary key of the GSI. You can only use the `eq` operator with this predicate.
For the schema defined above `User.LASTNAME.eq("Doe")` is a valid query expression.
Optionally, you can also chain the sort key to this expression, using any of the following operators: `eq | ne | le | lt | ge | gt | beginsWith | between`.
E.g., `User.LASTNAME.eq("Doe").and(User.CREATEDAT.gt("2020-10-10"))`.
Both of these sync expressions will result in AWS AppSync retrieving records from Amazon DynamoDB via a query operation:
```dart
Future initializeSingleEquals() async {
// Using eq operator with the primary key of the GSI
final singleEqualsStore = AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(
User.classType,
() => User.LASTNAME.eq("Doe"),
),
],
);
await Amplify.addPlugin(singleEqualsStore);
}
Future initializeChainedEquals() async {
// Using eq operator with the primary key of the GSI and
// chaining the gt operator with the sort key
final chainedEqualGtStore = AmplifyDataStore(
modelProvider: ModelProvider.instance,
syncExpressions: [
DataStoreSyncExpression(
User.classType,
() => User.LASTNAME.eq("Doe").and(User.CREATEDAT.gt("2020-10-10")),
),
],
);
await Amplify.addPlugin(chainedEqualGtStore);
}
```