🐷

Amplify&GraphQLでデータを取得するときにソートするために

2021/02/01に公開

はじめに

色々なチュートリアル系のハンズオンを実装する中でソートについてあまり触れられておらず、どうやって実装するんだろうと疑問になったのでまとめてみました。

想定シチュエーション

サービスにアイコン等のファイルを登録することを想像しています。private

触れること触れないこと

クライアントにはreactを使って試しているので、各種ツールのセットアップやcreate-react-app, amplify initあたりが終わったところから先の話になります。

参考記事

https://qiita.com/too/items/cb1dfb4f44536a3e9855

https://docs.amplify.aws/lib/storage/getting-started/q/platform/js#using-amazon-s3

お話の流れ

  1. amplify auth, amplify storage, amplify pushする
  2. reactのアプリケーション実装
  3. テスト

schema.graphqlの書き換え

私のamplifyの導入の仕方では
プロジェクトディレクトリ/amplify/backend/api/[pj名]/schema.graphql
にファイルがあります。

schema.graphql
type Post @model{ 
   id: ID!
   postOwnerId: String!
   postOwnerUsername: String!
   postTitle: String!
   postBody: String!
   createdAt: String
}

こんな感じのスキーマを書いた状態でamplify pushするとDynammoDBには

こんなテーブルができます。id(文字列)がパーティションキー、-がソートキーとなっています。

また、この時出来上がるクエリは

この二つ。idを指定して値を得るか、すべてのデータをソートせずに(おそらく実際にはidに関連したある順番になる、という理解)もってくるか、になります。
listPostsの結果をソートしたかったのですが、受信後の世界でやる以外の方法がわからず一旦断念。

そこで

schema.graphql
type Post
  @model
  @key(
    name: "SortByCreatedAt"
    fields: ["postType", "createdAt"]
    queryField: "listPostsSortByCreatedAt"
  )
 {
  id: ID!
  postOwnerId: String!
  postOwnerUsername: String!
  postTitle: String!
  postBody: String!
  createdAt: String!
  postType: PostType!
}

enum PostType {
  OPEN
  SECRET
}

こんなスキーマに変更。postTypeを追加して、セカンダリインデックスを使うことによって、プライマリキーはIDのままになるため、id指定のgetPostと、postTypeを使ってcreatedAtでソートをしたデータを取得するという二つの機能をもたせることができるようになる、と理解しています。
(SECRETなやつ取得出来たらあかんやろというツッコミはぐっとこらえてください、ぱっと思いついたのがこれだったもので・・・)

確かに新しいインデックスができているように見えます。

query {
  listPostsSortByCreatedAt (postType: OPEN, sortDirection: DESC) {
    items {
      postTitle
      postBody
      createdAt
    }
  }
}

実際にこんなクエリを書くとpostTypeがOPENなものをcreatedAtでソートして持ってくることができました。

amplify push

このスキーマ変更の場合はエラーが起こらないと思います。
プライマリキーを書き換えるような変更をしている場合はエラーになります。(なりました)
その場合はschemaの該当@modelを全部コメントアウトしてamplify push -> コメントアウトを戻して再度amplify pushとすると、dynamoDBのテーブルを一回削除して新しくつくり直す、という形で更新ができるようです。
https://github.com/aws-amplify/amplify-cli/issues/3523

手元で色々試す際はオンラインの設定変更に時間もかかってしまうのでamplify mockで手元で色々実験するのが楽な気がしています。
https://docs.amplify.aws/cli/usage/mock#api-mocking-setup

フロントエンド(今回はreact)からqueryを発行する

https://docs.amplify.aws/lib/graphqlapi/query-data/q/platform/js#query-declarations
こちらを参考に。

  const getPosts = async () => {
    const result = await API.graphql({
      query: listPostsSortByCreatedAt,
      variables: { postType: "OPEN", sortDirection: "ASC" },
    });
    setPosts(result.data.listPostsSortByCreatedAt.items);
  };

こんな感じのコードでソート済みの結果が得られました。

今後調べたいことなど

今回の実装方法以外に調べていると@searchableを使う方法というのがあるようなのでまた調べたいと思います。
また、目的に対して今回の実装がリーズナブルなのかもDynamoDBの特性がつかめていないため、今後使ってみながら理解を深めていきたいと思います。

Discussion