-
-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Single Table Design: Support Patterns #568
Comments
Hi, In short - Dynamoid doesn't support explicitly anything related to the Single-Table design. Why? I suppose because its goal is to implement the ActiveRecord pattern. It seems to me that the classic ActiveRecord pattern contradicts with ideas of the Single-Table design with kind of schemeless/multi-schema items. But I can easily imagine that Single-Table design's approach may be implemented on top of ORM like Dynamoid. Or on top of any other DynamoDB client. That is I am not against supporting Single-Table design in Dynamoid. But I see benefits in separating new features and existing ActiveRecord-like approach. How strong should be this separation? I don't know right now. It depends probably on how natural specific features look from the point of view of the ActiveRecord approach. Regarding the proposed feature with a range prefix. I am not familiar with the concrete patterns of the Single-Table design and don't know whether such range prefixes is a common/well known pattern. Could you please point at resources that describe such patterns? |
I totally second this idea of @bmalinconico. The prefix in range keys to differentiate between different types of data is THE access pattern in DynamoDB. Especially also when combined with a prefix and a date like "FUEL_PRICE#2022-09-19" … I'd really appreciate if Dynamoid would support this out of the box. The advantages are obvious, especially in terms of pricing/capacity. Having one big table instead of lots of small table with their own throttle settings is hindering application performance and simply unnecessarily costs money… |
@andrykonchin - Here's the official DynamoDB doc: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html |
@thomaswitt Thank you for the link. Probably I've got what you are talking about. @bmalinconico Yep, it seems it's a common approach to have a synthetic structured sort key. And it will be useful to support some predefined schemas. On the other hand such options like |
@andrykonchin Yes, basically you could already write this with the current version, but I'd say convention over configuration is a very old tried-and-true mantra of Rails. Apart from that, the way @bmalinconico described it, that's the way DynamoDB is originally intended to be used. I ran several huge DynamoDB based applications with tons of data and gazillions of rows. That's the only way to keep it scaling, and basically every AWS engineer will agree at an AWS summit. The way currently Dynamoids default is designed with multi table has a lots of drawbacks when you put it into production. That's why I think the project should offer more defaults in the way of @bmalinconico 's idea. The way how STI is currently implemented with the Type field is basically more band-aid. It should be a prefix in the range key. That would make also lots of other stuff easy. When I started using Dynamoid I ran e.g. into this problem: #501. It'd be way more easier if in that example Company and Report would have the same primary key and then you could filter via Range Key what you really want to get, either the company data or the report data. I started using Dymanoid because it was very convenient and used (despite my better knowledge) the multi table approach in the beginning. I then later had to painfully rewrite the whole app to use STI in a single table, with all model classes inheriting from a Bass Class which then defines table. Still there's a lot of code in my application with like Model.where(id: id_to_search_for, metadata.begins_with: 'REPORT#'), etc. With smart range keys like COMPANY# and COMPANY#REPORT you can easily get a company and all its all reports with a single query. All in all - just my two cents, I'd really appreciate if the single table approach would be promoted more as at least one of two default approaches and easily supported within the software, without having to write hooks, etc. |
Could you elaborate a bit more on how the prefix is supposed to work? What value it should be added to? At what moment - creation or every model updating? |
@andrykonchin A full design I would need to think about longer, but how I would approach it if you configure Dynamoid that way (let's say via config.single_table_design = true):
|
@andrykonchin Hey Andrii, just checkin in whether you had time to think about those suggestions … |
@andrykonchin Just a little ping. Have you given those ideas some thought? |
I use STI with Dynamoid. My approach is to not have a range key and use shared GSI columns with redundant data. GSI columns are set with before actions and can include values from multiple columns as needed. Much of this logic can be abstracted into a parent class so using it in the models isn't excessive. I have 5 GSIs that are string-string and 5 that are are string-number. If I needed pizzas created by user 1 sorted by timestamp I would use a GSI e.g.
If you don't like the redundant data and want to keep using range keys I suppose you could set the range key with a before action. You'd need to create new or override existing finders, however. |
@ckhsponge ckhsponge I understand your approach, but the range key was invented for a reason (also in terms of data distribution). Especially also as the idea in dynamo is that you don't delete by default but rather insert new data to have a built in history, the range key comes very handy. In that sense Dynamoid is written in a way that tries to emulate ActiveRecord, but does not embrace the ideas of DynamoDB. Unfortunately @andrykonchin doesn't seem to be open/interested to build another way which I described above which is more built like DynamoDB wants it, so I am considering to write an own lightweight Gem adapter to embrace these concepts. Especially as it makes sense to combine this with OpenSearch/ElasticSearch, which is also currently PITA as most gems (like SearchKick) won't work out of the box. DynamoDB + Opensearch is a very powerful combination - and it deserves to be supported for Rails out of the box the way it's meant to be. |
@thomaswitt I like your motivation! I am also a fan of Opensearch. If I understand correctly, using a GSI with all attributes projected could be wasting space but it does keep the items distributed as desired since it maintains a complete copy. I do think you could accomplish what you need to with an extension on top of Dynamoid e.g. shared before-create actions and custom finders. Reworking the innards of Dynamoid to handle that would probably be possible as well although would be more involved. |
I want to use Dynamo the way it's designed and intended to be used, and I would love a Ruby library that makes these patterns easier to use. Unfortunately, Dynamoid is not the answer today. @thomaswitt please let me know if you make any efforts in your own adapter/gem. I would be happy to contribute |
@bholzer I agree. Would you be open to throw some ideas together and do an outline of what should be in scope for a ruby lib? |
Hello,
I wanted to have a conversation as to how, and if at all, Dynamoid supports the common single table design for DynamoDB.
The basic TL;DR; is the existing STI with some Range Key magic. The Hash Key represents the ability to get all of a common thing, I'm going to use Pizza with a kinda contrived example.
This breaks down with the Dynamoid STI implementation.
I'd like to open a conversation about updating the ORM to allow for this pattern and want to toss around some options then identify what would need to be updated to work.
You can query for all toppings on a pizza by using Pizza ID and RK Prefix
First Idea
Allow a range prefix to be specified
The text was updated successfully, but these errors were encountered: