【Rails】AWS:DynamoDBのORM「Dynamoid」の不便な点とその改善方法(その1)
DynamoDBについて
皆さんは、AWSのNoSQLデータベース「DynamoDB」を利用していますか?
DynamoDBは、テーブル毎にスループット容量を設定できることと、主にその設定値によって利用料が決まることが特徴です。
データ容量による課金ではないため、大量データの管理が高額にならず、利用が集中するテーブルや時間に合わせて、スループット容量と利用料のバランスを調整することができます。
あ、もちろんAmazonなので、速度は折り紙つきです。
弊社はデータ管理に複数のDBを利用していますが、上記の特徴から、件数が大量のデータやアクセスが集中しやすいデータの場合は、DynamoDBを利用しています。
さて、DynamoDBを利用するにあたり、性能は全く申し分ないのですが、いざRuby on Railsでデータ操作のコードを書くとなると、公式のORMが今ひとつ使いにくいことに気が付きます。
aws-sdkの「AWS::Record::HashModel」というクラスなのですが、使いにくい例を挙げると…
- ActiveRecordの文法に似せてあるものの書き方が古かったり
- わざわざテーブルのスキーマ情報を取得する必要があったり
- etc…
Dynamoidを使う
そこで、「Dynamoid」というgemを利用してみます。
Veraticus/Dynamoid · GitHub
aws-sdkをラップし、よりActiveRecordに近い形で操作可能になっており、おすすめです。
Dynamoidはテーブル名に制約がかかってしまう
前段が長くなってしまいましたが、ここからが本題です。
このDynamoidは、どうやら初期のテーブル作成から使用されることを想定しているようで、テーブル名の命名規則にいくつか制限がかかってしまいます。
- 先頭に固定のnamespaceが付けられる
- 英小文字のスネークケースとなる
- 複数系(最後にsが付く)
例えば、下記のようにnamespaceを設定し、
Dynamoid.configure do |config| config.namespace = "test" end
下記のようにModelを作成したとすると、
class User include Dynamoid::Document ... end end
UserModelのアクセス先のテーブル名は「test_users」となってしまうのです。
これは、命名規則にマッチしないテーブルが既に存在する場合に、かなりの痛手です。
なにせDynamoDBはテーブル名の変更はできませんので、本気でやるなら新規テーブル作成後、データ移行するという手順を踏むことになります。
悲しい…orz
テーブル名の制約の対処方法
この問題に対処するため、Rubyのオープンクラスの特性を活かして、Dynamoidのコードを外部から書き換えます。
module Dynamoid module Persistence module ClassMethods def table_name ## Config.namespaceを付加しないよう書き換え #@table_name ||= "#{Dynamoid::Config.namespace}_#{options[:name] || base_class.name.split('::').last.downcase.pluralize}" @table_name ||= "#{options[:name] || base_class.name.split('::').last}" end end end end
コメントアウトの文と見比べていただければ、処理内容は単純なのでお分かりかと思います。 このコードをModel使用前に読み込ませることで、テーブル名の制約を取っ払うことができます。