Customize primary keys
Customize primary keys
By default, DataStore models have an id field that is automatically populated on the client with a UUID v4, allowing DataStore to generate non-colliding globally unique identifiers in a scalable way. While UUIDs have desirable properties (they are large, non-sequential and opaque), there are times when a custom primary key, also known as custom identifier, is needed. For instance, to:
- Have friendly/readable identifiers (surrogate/opaque vs. natural keys)
- Define composite primary keys
- Customize data partitioning to optimize for scale (especially important when planning to handle large amounts of data in short periods of time)
- Selectively synchronize data to clients (e.g. by fields like
deviceId,userIdor similar) - Prioritize the sort order in which objects are returned by the sync queries
- Make existing data consumable and syncable by DataStore
A schema with the typical id field looks like this:
type Book @model { id: ID! title: String! description: String}You can customize the primary key by adding the @primaryKey directive to a field:
type Book @model { isbn: ID! @primaryKey title: String! description: String}You can also require multiple fields to define your primary key. When your primary key references multiple fields, it's called a composite key. In the example below, the primary key is defined by the isbn and title fields:
type Book @model { isbn: ID! @primaryKey(sortKeyFields: ["title"]) title: String! description: String}Determine when the primary key field is auto-populated upon record creation
When you create a record with DataStore, a UUID is automatically populated for the default id: ID! primary key field. When working with custom primary keys, DataStore will automatically populate the key fields in the following conditions:
| Description | Type | Autopopulated with UUID |
|---|---|---|
Without | | ✅ Yes |
Without | | ✅ Yes |
| | ❌ No |
Explicit | | ✅ Yes |
Explicit | | ✅ Yes |
Explicit | | ✅ Yes |
@primaryKey with no | | ❌ No |
Querying records with custom primary keys
In addition to querying by the model type (or Predicates.ALL), a record with a custom primary key can be queried several ways.
With the value of the primary key:
const book = await DataStore.query(Book, '12345');With a predicate:
const books = await DataStore.query(Book, b => t.isbn.eq('12345'));const books = await DataStore.query(Book, b => b.and( b => [ b.isbn.eq('12345'), b.title.eq('My Book') ]));With an object literal:
const book = await DataStore.query(Book, { isbn: '12345' });// Both keys are required for composite keysconst book = await DataStore.query(Book, { isbn: '12345', title: 'My Book',});Deleting records with custom primary keys
In addition to deleting by the model type (or Predicates.ALL), a record with a custom primary key can be deleted the following ways:
With the value of the primary key:
const book = await DataStore.delete(Book, '12345');With a predicate:
const book = await DataStore.delete(Book, b => b.isbn.eq('12345'));const book = await DataStore.delete(Book, b => b.and([ b.isbn.eq('12345'), b.title.eq('My Book')]));With an object literal:
const book = await DataStore.delete(Book, { isbn: '12345' });const book = await DataStore.delete(Book, { isbn: '12345', title: 'My Book',});