0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DynamoDB + Railsで投稿のもっと見るボタンを作る

Posted at

0. はじめに

SNSツールを作るにあたり、key-valueストアであるDynamoDBを選択した。これは、大量のデータの中から任意のキーで検索をかけることで、より高速にデータを取得できるDBになっている。今回はRailsアプリを使って実装した内容を書いていく。

1. Dynamo DBの設計

RailsのgemであるDyanmoidを利用して、DynamoDBにデータを保存する。
その際、hasy_keyをtimeline_idに設定した。hasy_keyはデフォルトでユニークな文字列型となっている。

module Dynamo
  class Timeline
    include Dynamoid::Document

    table name: :timelines, key: :timeline_id, capacity_mode: :on_demand, timestamps: false

    field :body, :string
    field :created_user_id, :integer
    field :process_at, :integer, default: -> { Time.zone.now.to_i }
  end
end

2. GSIの設定

DynamoDBではhash_keyに指定した属性以外で検索をかけると、SCAN操作(DB全体の検索)になってしまう。
そのため、QUERY操作(hash_keyでの検索)になるように、GSI(Global Secondary Index)
を設定する。
今回はTOPページで全ての投稿を表示するため、created_user_idなど、固定値のhash_keyが存在しない。そのため、固定値であるSORT_HASH_KEYをhash_keyとして新たに設定することでQUERY操作を実現した。
なお、range_keyはItemの並び替えに使われる。

    SORT_HASH_KEY = 1

    field :sort_hash_key, :integer, default: SORT_HASH_KEY

    global_secondary_index hash_key: :sort_hash_key, range_key: :process_at,
                           name: :sort_hash_key_process_at_index, projected_attributes: :all

3. 指定した値分の投稿を取得

まずは、初回リクエストでper_page分だけ、投稿を取得するメソッドを実装。
最後に評価した値(last_evaluated_key)をreturnする必要があるため、find_by_pagesメソッドを使う。
なお、scan_index_forward(false)メソッドで、range_keyの降順に並び替えられる。
今回は最新の投稿から取得するように実装している。

    class << self
      def next_page_of_timelines(per_page)
          paginate_items(by_sort_hash_key, per_page)
      end

      private

      def by_sort_hash_key
        where(sort_hash_key: SORT_HASH_KEY).scan_index_forward(false)
      end

      def paginate_items(chain, per_page)
        chain.record_limit(per_page).find_by_pages.first
      end
    end

4. もっと見る機能の実装

続いて、2回目以降のリクエスト時には、last_evaluated_keyがparamsとして渡されるので、last_evaluated_key + 1番目から、per_page分の投稿を取得する。
そのためstart_keyメソッドを活用して、取得する最初の値を特定する。

    class << self
      def next_page_of_timelines(timeline_id, process_at, per_page)
        if timeline_id.blank? && process_at.zero?
          paginate_items(by_sort_hash_key, per_page)
        else
          paginate_items(start_key(by_sort_hash_key, timeline_id, process_at), per_page)
        end
      end

      private

      def by_sort_hash_key
        where(sort_hash_key: SORT_HASH_KEY).scan_index_forward(false)
      end

      def start_key(chain, timeline_id, process_at)
        chain.start(timeline_id:, process_at:, sort_hash_key: SORT_HASH_KEY)
      end

      def paginate_items(chain, per_page)
        chain.record_limit(per_page).find_by_pages.first
      end
    end

これで、DynamoDBから任意の値を適切に取得するRails側の実装ができる。
なお、created_user_idなど、固定のhash_keyがあれば、今回のようにSORT_HASH_KEYのような固定値をわざわざ設ける必要性がなくなる。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?