Relational models
DataStore has the capability to handle relationships between Models, such as has one, has many, belongs to. In GraphQL this is done with the @hasOne
, @hasMany
and @index
directives as defined in the GraphQL Transformer documentation.
Updated schema
For the examples below with DataStore let's add a new model to the sample schema:
1enum PostStatus {2 ACTIVE3 INACTIVE4}5
6type Post @model {7 id: ID!8 title: String!9 rating: Int!10 status: PostStatus!11 # New field with @hasMany12 comments: [Comment] @hasMany13}14
15# New model16type Comment @model {17 id: ID!18 post: Post @belongsTo19 content: String!20}
Saving relations
In order to save connected models, you will create an instance of the model you wish to connect and pass its ID to DataStore.save
:
1const post = await DataStore.save(2 new Post({3 title: 'My Post with comments',4 rating: 10,5 status: PostStatus.ACTIVE6 })7);8
9await DataStore.save(10 new Comment({11 content: 'Loving Amplify DataStore!',12 post: post13 })14);
Querying relations
You can query related models in three ways:
- Option 1: use the
toArray()
function to lazy load related comments
1const post = await DataStore.query(Post, "YOUR_POST_ID")2if (post) {3 const comments = await post.comments.toArray()4}
- Option 2: use async iterators to lazy load related comments
1const post = await DataStore.query(Post, "YOUR_POST_ID");2if (post) {3 for await (const comment of post.comments) {4 console.log(comment)5 };6}
- Option 3: use nested query predicates with the
Comment
model
1const comments = await DataStore.query(Comment, c => c.post.id.eq('YOUR_POST_ID'));
Deleting relations
When you delete a parent object in a one-to-many relationship, the children will also be removed from the DataStore and mutations for this deletion will be sent over the network. For example, the following operation would remove the Post with id 123 as well as any related comments:
1const toDelete = await DataStore.query(Post, "123");2if (toDelete) {3 DataStore.delete(toDelete);4}
However, in a many-to-many relationship the children are not removed and you must explicitly delete them.
Many-to-many
For many-to-many relationships, you can use the @manyToMany
directive and specify a relationName
. Under the hood, Amplify creates a join table and a one-to-many relationship from both models.
1enum PostStatus {2 ACTIVE3 INACTIVE4}5
6type Post @model {7 id: ID!8 title: String!9 rating: Int10 status: PostStatus11 editors: [User] @manyToMany(relationName: "PostEditor")12}13
14type User @model {15 id: ID!16 username: String!17 posts: [Post] @manyToMany(relationName: "PostEditor")18}
1// first you save the post2const post = await DataStore.save(3 new Post({4 title: 'My first post'5 })6);7
8// secondly, you save the editor/user9const editor = await DataStore.save(10 new User({11 username: 'Nadia'12 })13);14
15// then you save the model that links a post with an editor16await DataStore.save(17 new PostEditor({18 post: post,19 user: editor20 })21);