How to model one-to-many relationships with AppSync and DynamoDB
Tags: appsync, aws, dynamodb
Published: 2021-03-28 21:07:22

---
title: How to model one-to-many relationships with AppSync and DynamoDB
published: true
date: 2021-03-27 20:30:30 UTC
tags: AppSync,AWS,DynamoDB
canonical_url: https://appsyncmasterclass.com/how-to-model-one-to-many-relationships-with-appsync-and-dynamodb/
---

Thank you to Josh for asking this question on the [AppSync Masterclass](https://appsyncmasterclass.com/) forum. His original question goes like this:

> _Let’s say I want to add a one-to-many relationship from Profile to a new property called “Tag” (a complex object with “name” and “color” properties) so a user can define their own Tags. I would also like a Tweet to reference one or more of the user’s own Tags. The Tag(name, color) object can change over time (the “name” can be renamed for example) so I don’t think I want to copy it into a Tweet._
> 
> _Do you have an example of something like that you could point me to? Would “Tag” be a new DynamoDB table in this case, or is there a better way to model it so it can be referenced in a Tweet? Would I store Tag ids in an array on the Tweet table item? Would I need a “creator” column in the Tag table, like we already have on the Tweet table?_

![](https://theburningmonk.com/wp-content/uploads/2021/03/img_605f958b3c714.png)

To answer this question, there are two aspects we need to consider:

1. How to represent this one-to-many relationship in the GraphQL model?

2. How to model this one-to-many relationship in DynamoDB?

Both depend on if the `tags` array’s length is unbounded.

For example, if you include a `tweets` array in `IProfile` interface then I would say for sure that it’s an unbounded array. Whereas `tags` is usually a bounded array.

## Modelling in GraphQL schema

If it’s a bounded array, then the example Josh included makes sense, the only change I’d make is to change the `tags` array to:

```
interface IProfile {
  ...
  tags: [Tag!]
}
```

This is so that you can’t return `null` in the `tags` array.

If it’s an unbounded array, like `tweets`, then you should return something like the `TweetsPage` type we have:

```
interface IProfile {
  ...
  tweets: TweetsPage!
}

type TweetsPage {
  tweets: [ITweet!]
  nextToken: String
}
```

Essentially, you attach the first page of the user’s tweets (with a pre-determined page size) and give the caller a way to fetch more if they want (with a query like `getTweets(limit: Int!, nextToken: String)`).

## Modelling in DynamoDB

For a bounded array, I find it easier (so long the nested items aren’t huge, and the max array size is relatively small) to nest the array in the `Profile` object.

For an unbounded array, nesting wouldn’t work because there’s a hard limit on the size of each DynamoDB object. And the cost of reading the item from DynamoDB can be excruciating since DynamoDB calculate read units based on the size of the items returned.

You can model these in a number of ways.

Using single-table design [this](https://www.alexdebrie.com/posts/dynamodb-one-to-many) would be how you do it.

Or you could follow the approach we have taken in the [AppSync Masterclass](https://appsyncmasterclass.com/) and put them in a separate table (like the `TweetsTable` where the HASH key is the userId).

Personally, I’d go with using a separate table – it’s just much simpler:

- You write less custom VTL code in VTL templates.
- It’s easy to understand what data you have in a table.
- You can monitor the cost for different tables and see how much each type of data is costing you to store and access and therefore where to optimize your data access code.
- You can (more easily) use DynamoDB streams to react to data changes.
- It’s easy to follow the least privilege principle and restrict access to data in DynamoDB.
- Plus, GraphQL and AppSync are great at stitching the data together.

If you listen to our last **[live Q&A session](https://www.youtube.com/watch?v=YoYVbdTnCzY)**, we talked about the benefits of single-table design and why in most cases they wouldn’t matter to you anyway unless you’re running a very high throughput workload and you need to optimize for cost.

And if you want to learn more about AppSync and GraphQL, then check out my video course – **[the AppSync Masterclass](https://appsyncmasterclass.com/)** – and  **save 30%**  while we’re still in early access!

![](https://theburningmonk.com/wp-content/uploads/2020/11/img_5fb41b129e5fd.png)