aws / aws-sdk-ruby-record

Official repository for the aws-record gem, an abstraction for Amazon DynamoDB.
Apache License 2.0
318 stars 41 forks source link

Configuration with a Single Table #92

Closed LastZactionHero closed 2 years ago

LastZactionHero commented 5 years ago

I've been this library into a new Ruby application running on AWS Lambda. Overall, I'm new to Lambda and Dynamo DB, so I apologize if some of this is obvious.

Per the Dynamo DB docs, it seems that a well structured application should include only one table. I've reviewed some AWS documentation and videos on how to structure keys and indexes to include a variety of information in single table while still maintaining the ability to query for distinct pieces of data, rather than say a separate User, Product, Order table.

However, my reading of this library and some examples seems to imply the use of several tables- in particular, defining specific properties/indexes on the model, and taking this model as an argument to TableMigration.

Is the expectation that this library is used with a single-table application?

awood45 commented 5 years ago

You absolutely can, and this is an encouraged pattern. I've generally done this by way of convention (inheritance and this library don't play as nicely as I'd like). Consider this possible approach where all of your unique IDs are UUID-based. You'd start with a base table:

class BaseTable
  include Aws::Record
  set_table_name ENV["TABLE_NAME"] # good practice for testing
  string_attr :hk, hash_key: true
  string_attr :rk, range_key: true
end

You might then implement tables like so:

class User
  include Aws::Record
  set_table_name ENV["TABLE_NAME"]
  string_attr :user_id, hash_key: true, database_attribute_name: 'hk'
  string_attr :table_name, range_key: true, database_attribute_name: 'rk' # always 'USER' for this table
  # add user attributes
end

class Product
  include Aws::Record
  set_table_name ENV["TABLE_NAME"]
  string_attr :product_id, hash_key: true, database_attribute_name: 'hk'
  string_attr :table_name, range_key: true, database_attribute_name: 'rk' # always 'PRODUCT' for this table
  # add product attributes
end

class Order
  include Aws::Record
  set_table_name ENV["TABLE_NAME"]
  string_attr :order_id, hash_key: true, database_attribute_name: 'hk'
  string_attr :table_name, range_key: true, database_attribute_name: 'rk' # always 'ORDER' for this table
  # add order attributes
end

You can also represent one-to-many relationships with shared hash keys and then using the range keys as the unique identifier. Basically, anything shown in the best practices document for DynamoDB, you should be able to model as virtual tables.

awood45 commented 5 years ago

Happy to help if you have any questions about how a particular table design would map to DynamoDB. One important thing to keep in mind is that the base table should include any global secondary indexes as well, and is what you should use for migrations.

LastZactionHero commented 5 years ago

Thanks for the tips! Makes sense. I'd seen some alternatives to hk/rk as UUID/modelname from an AWS video.

That would actually be really helpful- I'm building a fairly simple microservice, first time using Lambda/DynamoDb, and could use some input on the best way to structure it - zach@workbright.com