Amplify&GraphQLでデータを取得するときにソートするために
はじめに
色々なチュートリアル系のハンズオンを実装する中でソートについてあまり触れられておらず、どうやって実装するんだろうと疑問になったのでまとめてみました。
想定シチュエーション
サービスにアイコン等のファイルを登録することを想像しています。private
触れること触れないこと
クライアントにはreactを使って試しているので、各種ツールのセットアップやcreate-react-app, amplify initあたりが終わったところから先の話になります。
参考記事
お話の流れ
- amplify auth, amplify storage, amplify pushする
- reactのアプリケーション実装
- テスト
schema.graphqlの書き換え
私のamplifyの導入の仕方では
プロジェクトディレクトリ/amplify/backend/api/[pj名]/schema.graphql
にファイルがあります。
type Post @model{
id: ID!
postOwnerId: String!
postOwnerUsername: String!
postTitle: String!
postBody: String!
createdAt: String
}
こんな感じのスキーマを書いた状態でamplify pushするとDynammoDBには
こんなテーブルができます。id(文字列)がパーティションキー、-がソートキーとなっています。
また、この時出来上がるクエリは
この二つ。idを指定して値を得るか、すべてのデータをソートせずに(おそらく実際にはidに関連したある順番になる、という理解)もってくるか、になります。
listPostsの結果をソートしたかったのですが、受信後の世界でやる以外の方法がわからず一旦断念。
そこで
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のテーブルを一回削除して新しくつくり直す、という形で更新ができるようです。
手元で色々試す際はオンラインの設定変更に時間もかかってしまうのでamplify mockで手元で色々実験するのが楽な気がしています。
フロントエンド(今回はreact)からqueryを発行する
こちらを参考に。
const getPosts = async () => {
const result = await API.graphql({
query: listPostsSortByCreatedAt,
variables: { postType: "OPEN", sortDirection: "ASC" },
});
setPosts(result.data.listPostsSortByCreatedAt.items);
};
こんな感じのコードでソート済みの結果が得られました。
今後調べたいことなど
今回の実装方法以外に調べていると@searchableを使う方法というのがあるようなのでまた調べたいと思います。
また、目的に対して今回の実装がリーズナブルなのかもDynamoDBの特性がつかめていないため、今後使ってみながら理解を深めていきたいと思います。
Discussion