Amplify GraphQLで[Int]型のフィールドでContainsオペレーターを利用する
結論
AWS Appsyncのスキーマで該当する型(ModelIntInput
)を手動でアップデートし、contains: Int
を追加する。
はじめに
AWS AmplifyではデータベースとしてGraphQLを利用することができ、ユーザはGraphQLスキーマを定義するだけでAppSyncやDynamoDBの設定をすることなく利用することができます。 しかし、クエリのfilterで、[Int]型のフィールドに対して、本来利用ができるはずのcontainsオペレータが利用ができず苦しんだので備忘録を残しておきます。
Version
"aws-amplify": "^5.3.3"
Example schema
以下のようなUser
テーブルがschema.graphql
として定義されているとします。
type User @model @auth(rules: [{ allow: public }]) { id: ID! favoriteNumbers: [Int]! }
ここで、
id
: ユーザに一意に付与されるIDfavoriteNumbers
: ユーザが好きな数字のリスト
とします。
こちらのスキーマ定義をamplify push api
すると、User tableに対するqueryやmutationを実行することができます。
Contains operator
ここで、User tableからUserのリストを取得することを考えます。 GraphQLクエリは以下のようになるでしょう。
const listUsers = /* GraphQL */ ` query ListUsers($filter: ModelUserFilterInput, $limit: Int, $nextToken: String) { listUsers(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id favoriteNumbers } } } `;
ここで、「ある特定の数字が好きなユーザのリストを取得する」ことを考えます。すると、各レコードのfavoriteNumbers
に格納されている[Int]型の値の中に特定のInt値が含まれているかどうかを確認する必要があります。
AmplifyでGraphQLを利用する時には裏側でDynamoDBを利用することになりますので、DynamoDBでこのような演算子が利用できるかを確認します。
Comparison operator and function reference - Amazon DynamoDB
こちらに、
A List that contains a particular element within the list.
とあることから、contains
というオペレータを利用することで、[Int]に特定の要素が含まれているレコードを取得することができそうです。
しかし、上記のlistUsersを用いてクエリを実行しても、うまくfliterが効かないです。
以下は、ある特定の数字num
をお気に入りにしているユーザの一覧を取得するための関数fetchUsers
です。
import { API } from "aws-amplify"; const listUsers = /* GraphQL */ ` query ListUsers($filter: ModelUserFilterInput, $limit: Int, $nextToken: String) { listUsers(filter: $filter, limit: $limit, nextToken: $nextToken) { items { id favoriteNumbers } } } `; const fetchUsers = async (num)=> { const variables = { filter: { favoriteNumbers: { contains: num } }, }; const response = await API.graphql({ query: listUsers, variables: variables }); }
AppSync
AppSyncは、AWSフルマネージドサーバーレス GraphQL API サーバーです。
該当するAPIの「スキーマ」を確認し、フィールド favoriteNumbers
に対応するスキーマを確認すると
input ModelIntInput { ne: Int eq: Int le: Int lt: Int ge: Int gt: Int between: [Int] attributeExists: Boolean attributeType: ModelAttributeTypes }
となっていることが分かります。どうやら、ここで利用可能なオペレータを定義しているようです。
ここでcontains
オペレータを手で追加してください。そうすればcontains オペレータを用いたfilterが有効になります。
input ModelIntInput { ne: Int eq: Int le: Int lt: Int ge: Int gt: Int between: [Int] contains: Int attributeExists: Boolean attributeType: ModelAttributeTypes }
注意
このAppSyncスキーマはamplify push api
を実行するたびにリセットがされるため、containsオペレータを利用するためには毎回手動でAppSyncのスキーマを編集しなければいけません。
なお、Int型以外のString型に対しては自動でcontainsオペレータが追加されますので上記の操作は必要ありません。