PCがあれば何でもできる!

へっぽこアラサープログラマーが、覚えたての知識を得意げにお届けします

【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使用前に読み込ませることで、テーブル名の制約を取っ払うことができます。