Amplify2.2.5の仕様のままでは不可能

厳格に言うと、AppSyncの中のマッピングテンプレートを変更すれば対応は可能な様子。

ただデプロイする度に消えるから推奨しない、開発効率最悪だよね。(build/配下に展開されデプロイされるので)

とりあえずこのパターン紹介しておきます。

マッピングテンプレート修正箇所について

Queryリゾルバー、レスポンスマッピングテンプレートの該当箇所

#set( $es_items = [] )
#foreach( $entry in $context.result.hits.hits )
  #if( !$foreach.hasNext )
    #set( $nextToken = $entry.sort.get(0) )
  #end
  $util.qr($es_items.add($entry.get("_source")))
#end

## [Start] Determine request authentication mode **
#if( $util.isNullOrEmpty($authMode) && !$util.isNull($ctx.identity) && !$util.isNull($ctx.identity.sub) && !$util.isNull($ctx.identity.issuer) && !$util.isNull($ctx.identity.username) && !$util.isNull($ctx.identity.claims) && !$util.isNull($ctx.identity.sourceIp) && !$util.isNull($ctx.identity.defaultAuthStrategy) )
  #set( $authMode = "userPools" )
#end
## [End] Determine request authentication mode **
## [Start] Check authMode and execute owner/group checks **
#if( $authMode == "userPools" )
  ## [Start] Static Group Authorization Checks **
  #set($isStaticGroupAuthorized = $util.defaultIfNull(
            $isStaticGroupAuthorized, false))
  ## Authorization rule: { allow: groups, groups: ["admin"], groupClaim: "cognito:groups" } **
  #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
  #set( $allowedGroups = ["admin"] )
  #foreach( $userGroup in $userGroups )
    #if( $allowedGroups.contains($userGroup) )
      #set( $isStaticGroupAuthorized = true )
      #break
    #end
  #end
  ## Authorization rule: { allow: groups, groups: ["customer"], groupClaim: "cognito:groups" } **
  #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
  #set( $allowedGroups = ["customer"] )
  #foreach( $userGroup in $userGroups )
    #if( $allowedGroups.contains($userGroup) )
      #set( $isStaticGroupAuthorized = true )
      #break
    #end
  #end
  ## Authorization rule: { allow: groups, groups: ["agency"], groupClaim: "cognito:groups" } **
  #set( $userGroups = $util.defaultIfNull($ctx.identity.claims.get("cognito:groups"), []) )
  #set( $allowedGroups = ["agency"] )
  #foreach( $userGroup in $userGroups )
    #if( $allowedGroups.contains($userGroup) )
      #set( $isStaticGroupAuthorized = true )
      #break
    #end
  #end
  ## [End] Static Group Authorization Checks **


  ## [Start] If not static group authorized, filter items **
  #if( !$isStaticGroupAuthorized )
    #set( $items = [] )
    #foreach( $item in $es_items )
      ## No Dynamic Group Authorization Rules **


      ## No Owner Authorization Rules **


      #if( ($isLocalDynamicGroupAuthorized == true || $isLocalOwnerAuthorized == true) )
        $util.qr($items.add($item))
      #end
    #end
    #set( $es_items = $items )
  #end
  ## [End] If not static group authorized, filter items **
#end
## [End] Check authMode and execute owner/group checks **

#set( $es_response = {
  "items": $es_items
} )
#if( $es_items.size() > 0 )
  $util.qr($es_response.put("nextToken", $nextToken))
  $util.qr($es_response.put("total", $es_items.size()))
#end
$util.toJson($es_response)

こんな具合にすれば検索結果総数の取得は可能。

#if( $es_items.size() > 0 )
  ...
  $util.qr($es_response.put("searchTotal", $context.result.hits.total))  ← 追加
#end
$util.toJson($es_response)

$context.result.hits.totalでなぜ取得できるのか。

ElasticSearchにリクエストした際に取得できるレスポンス内容をみて欲しい。

$ curl -XGET https://search-amplify-elasti-xxxx-xxxxxx.ap-northeast-1.es.amazonaws.com/client/_search
{
    "took": 9,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 11,
        "max_score": 1.0,
        "hits": [
            {

hits以下にtotalがいるよね。これが総件数です。
(ただし総件数は10,000が最大値となるっぽいので、検索結果10,000以上になると10,000で返ってきます)

なぜAmplifyが対応しないのかは、このIssueを確認してみて欲しい。
近い将来対応される様子なので期待大。

本件に関連するIssue >> https://github.com/aws-amplify/amplify-cli/issues/1865

じゃあどのように対応するべきなのか

いずれかのように対応するが良いと思われます。

  • amplify add functionしてElasticsearchへリクエストする関数を作成し呼び出す(ESのエンドポイント情報は環境変数で渡すのがベストかな)
  • nextTokenがnullになるまで繰り返し検索しJSで集計(limitを1000にすればまぁリリース初期では2回から3回の呼び出しで済むと思う)

所感

今後に期待。GraphQLのQuery結果のtotalと並んでsearchTotal的なのも入ってきそう。