AWS AppSync で Amazon DynamoDB を使用したときに、リストクエリで間違った数の項目が返されています。解決方法を教えてください。
簡単な説明
AWS AppSync および Amazon DynamoDB でリストクエリを使用した場合、DynamoDB はテーブルに対して Scan オペレーションを実行し、一定数の評価済の項目を返します。リクエストで FilterExpression オペレーションを指定すると、DynamoDB はこれらの評価済の項目だけに FilterExpression を適用します。
Scan がチェックする項目の数は、クエリに適用した制限の変数によって異なります。制限が適用されていない場合、DynamoDB はリクエストマッピングテンプレートで設定されているデフォルトの制限値を使用します。Scan は、評価された、フィルター式に一致する項目だけを返します。求める数の項目を返すには、制限の変数を調整する必要があります。
マッピングテンプレートのデフォルトの制限値を引き上げるか、リストの GraphQL クエリに制限の変数を追加してください。ただし、評価できる項目は最大 1 MB です。Scan オペレーションが取得するデータが 1 MB を超える場合は、ページ分割を使用して残りのデータを取得できます。何千もの項目を含むデータベースにクエリを実行しやすくするには、データにインデックスを付けて、共通のフィールドで結果をフィルタリングします。
解決方法
デフォルトの制限値を引き上げる
次の AWS Amplify で生成された API のマッピングテンプレートの例では、デフォルトの制限は 100 です。
#set( $limit = $util.defaultIfNull($context.args.limit, 100) )
#set( $ListRequest = {
"version": "2018-05-29",
"limit": $limit
} )
さらに多くの項目を評価する場合は、マッピングテンプレートのデフォルト制限を変更します。または、制限変数をリストクエリに追加します。例えば、次のリストクエリでは、制限が「1,000」に設定されています。
query MyQuery {
listEmployees(limit: 1000) {
items {
id
name
company
}
}
}
AWS AppSync でページ分割する
AWS AppSync でページ分割するには、GraphQL クエリに nextToken 引数を追加します。
クエリの例:
query MyQuery {
listEmployees{
items {
id
name
company
}
nextToken
}
}
注: クエリが返す nextToken 値は、null か、ey で始まり = で終わる長い文字列のいずれかです。この値は、最後に評価されたキーを表します。値が null であれば、テーブルには評価する項目がこれ以上存在しません。長い文字列であれば、評価する項目が他にもあります。
例を以下に示します。
"nextToken": "eyJ2ZXJzaW9uIjoyLCJ0b2tlbiI6IkFRSUNBSGg5OUIvN3BjWU41eE96NDZJMW5GeGM4WUNGeG1acmFOMUpqajZLWkFDQ25BRkQxUjREaVVxMkd1aDZNZ2ZTMmhPMUFBQUNIVENDQWhrR0NTcUdTSWIzRFFFSEJxQ0NBZ293Z2dJR0FnRUFNSUlCL3dZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF4c0RFY1ZZUGpaRDFxbDcxNENBUkNBZ2dIUWkwaGtJYytoU04vRFMzL3VQT2ZDMnpIV1dBVkg4LzU3TWFwMGZWSHVackt1VmV4emRvTVQrNml6VC9RdDRsSVNGN1pmc3NWTHVvcnJpRE1RZVE5ckNyd3J4dmNOY3ZZUzhTc21PRFFkaTUreVhQcDJ1OENaK29Sd2wrV3VoOGJ0YlBpQXQydjRNdmw2L09jRzRHV2RxRmFjeTFDRjRyK2FPd29velRTV3NqMTd4OUpwVi93cHVYc2tTN2R5TmYxa3JJS3hSL3BMWlY5M3JPSlVocEpDV2xEL3Y1UU5JdGJoOWpyaTI3N09LbUZsVlh3bDRna3hDa1kzeGZMNjZrM2dZY0hpbHlUOE1GUnBLU0VCTFE3RGEzSlJtUG8xUkJvQ051K3dBTkwwd09Vckp0N1BFb0QvTVRrenZDV1lCTXhVaUhaRDdrM3Y5a2FJS2NScHY0ajhuTDJ2Nk9EZ3plTjgwN1RtRFViM21rRUsrakRRcjUvd3ZQVW56cGFaN1RnR21yT21FaTlGQklOUnl6dk9rdDRWazZEaVU3RCtNYUJSdm5iNnR0VklPa2lDdFlhODRqenhlOFlFRUZGOElyTksrQm9yL28vdktxMVczSUxsU1VWWFd0N0hPWjV4TDBudHVTeGlBdW9ZK1Y0NEkzMXlPQkJ1T1AwMVpUek1TdGUvZCtIT1RRUEt2SGVGanF5Y0tpNGNTQUdZN3BobGs5eWJJem9hOTM0YldJOUFyRmF0WDY4UnkzTkF4cWNCbzh4ZklxZGZNN3Rlam02NldMT0Z6T3F6MDRrK1B0K0lXdWhOeS9CWEN2YXh2dk09In0="
テーブル内の残りの項目を取得するには、nextToken をクエリ変数として使用する別のクエリを実行します。すべての項目が評価されるまで、nextToken 変数の使用を継続します。
クエリの例:
query MyQuery {
listEmployees(nextToken:"eyJ......="){
items {
id
name
company
}
nextToken
}
}
データのインデックスを作成する
次のクエリ例では、フィルター式が AnyCompany と等しい従業員に基づいたいくつかの項目を返すように設定されています。
query MyQuery {
listEmployees(filter: {company: {eq: "AnyCompany"}}) {
items {
id
name
company
}
nextToken
}
}
会社に基づいたすべての従業員を一覧表示するには、クエリ対象のフィールド用にグローバルセカンダリインデックスを作成します。例えば、Amplify では、@index ディレクティブを使用してセカンダリインデックスを定義できます。
type Employee @model{
id:ID
name : String
email : AWSEmail
company: String @index(name:"employeeByCompany", queryField: "listEmployeesByCompany")
}
次のクエリ例では、会社フィールドに GSI employeeByCompany が設定され、クエリは listEmployeesByCompany として定義されています。
query MyQuery {
listEmployeesByCompany(company: "AnyCompany") {
items {
id
name
company
}
nextToken
}
}
制限変数を指定して、データベース内の項目を意図した数だけ返すようにすることができます。例えば、次のクエリでは、制限変数が「5」に設定されています。
query MyQuery {
listEmployeesByCompany(company: "AnyCompany",limit:5) {
items {
id
name
company
}
nextToken
}
}
注: 制限変数を設定すると、追加の filterExpressions を適用した場合でも、意図した数の項目だけが返されます。例えば、次のクエリでは、制限変数が「5」に設定され、フィルターは Mary Major と等しくなっています。
query MyQuery {
listEmployeesByCompany(company: "AnyCompany",limit:5) {
name:{
eq:"Mary Major"
}
}) {
items {
id
name
company
}
nextToken
}
}
上記のクエリは、Mary Major と等しい項目を 5 つだけ返します。ただし、Mary Majors が 5 人以上存在する可能性があります。
注: インデックス付きクエリでも、一度に最大 1 MB のデータが返されます。より大きなサイズのインデックス付きクエリでは、ページ分割を使用できます。