beginner-corp / begin-data

A durable and fast key/value store for Begin built on top of DynamoDB
79 stars 8 forks source link

Q: How would you model one-to-many using @begin/data and DynamoDB? #39

Closed YarivGilad closed 4 years ago

YarivGilad commented 4 years ago

How would you model the following entities? User --> has many Posts Post --> each Post belongs to a single User Image --> each Image belongs to either a User or a Post or an Organisation Organisation --> each Organisation has many Users, each User can belong to many Organisations

Would you create each entity in a separate table and have a field pointing to an owner entity (a la FK)? Would you store all of them in one big Organisation table containing nested json fields, with denormalised data duplicated multiple times across different documents? if so - how would you go about updating a User field that belongs to several Organisations?

brianleroux commented 4 years ago

So we created @begin/data to make it easier to get started with DynamoDB doing simple persistence tasks. This is a perfect use case!

@begin/data

There is only one database table for all the data defined in an .arc app that uses @begin/data. It is defined as follows:

@app 
myapp

@tables
data
  scopeID *String
  dataID **String
  ttl TTL

The .arc above defines a single DynamoDB table with a partition key of scopeID and a sort key of dataID. This table can optionally have items that expire by setting the ttl attribute on rows

From here on reading and writing is done completely in code. @begin/data methods always have a table attribute but under the hood this is a virtual table of data! I would model the system with separate tables. A good convention is to use plural form of the noun the table represents. I'm not entirely sure what Image represents so I'm just going to focus on the user/org/post nouns.

let data = require('@begin/data')

// create a new org
await data.set({
  table: 'orgs', 
  key: 'engineering'
})

// adds a brand new user (and will automatically create key)
let user = await data.set({
  table: 'users',
  org: 'engineering',
  name: 'brian'
})

let post = await data.set({
  table: `users-${user.key}`,
  title: 'my post',
  body: 'some wisdom here'
})

Let me know if this makes sense so far!