Amplify schema GraphQL @keyについて完璧に理解する

Amplifyのschemaに指定する@keyとは何なのか、なぜ使う必要があるのかについてまとめましたので、これをみていただければ@keyをどう活用するのかを理解いただけるはずです。

@keyをなぜ使うのか

DynamoDBのクエリは、最大で二つのAttribute(AppSyncのフィールド)を使うのがよいとされている。

この二つのAttributeはPartition Key(PK)とSort Key(SK)と呼ばれる。

DynamoDBはPK単体、またはPKとSKを組み合わせてプライマリキーとして利用することができる。

だから、これら2つのキーを使用する。

でもなぜPKとSKを使う必要があるのか?

使うことによって、効率を上げ、時間と通信コストを削減することができる。

使わずにクエリを書く場合、DynamoDBのTableの中身全てをスキャンすることになり、非常に効率が悪い。

この2つのキーを指定することが@keyの主な役割なのである

データをランダムにしかフェッチ(取得)できない場合に、@keyを使用することでDynamoDBのインデックスを作成し、クエリを作成することができるんです。

AppSyncでは、 idが空の場合、 自動的にidを生成してidフィールドを埋めるが、入力を必須にするとクライアント側で渡す必要があり、自動生成機能を使えなくなってしまう。

実例

  @key(name: "SortByTimestamp", fields:["type", "timestamp"], queryField: "listPostsSortedByTimestamp")
  @key(name: "BySpecificOwner", fields:["owner", "timestamp"], queryField: "listPostsBySpecificOwner")
  • nameとは: DynamoDBのインデックス(Global Secondary Index)の名前
  • fieldsとは: 一つ目がPartition Keyに利用するフィールド、二つ目がSort Keyに利用するフィールド
    ひとつだけ書くと、Partition Keyのみがセットアップされる。
  • queryFieldとは: getPostのような、GraphQLのqueryの名前

上記2行はどのような働きをしているのか

listPostsSortedByTimestamp

typeフィールドをPKにすることで、全てのPostをフェッチすることができる。

timestampをSortKeyにすることで、timestampでの昇降順ソートが可能になる。

listPostsBySpecificOwner

・PKにownerを指定することで、あるownerのPostをリストアップすることができる。

結論

@keyは、通信にかかる時間とコストを削減するために使用し、ソートのやリストアップの働きをする。

追記:GraphQL v2

2021年11月に、GraphQLのバージョンアップがあり、この@keyの記述方法が大きく変更となったので変更内容をまとめました。

AWSより出されているドキュメントはこちら

AWS Amplify announces the new GraphQL Transformer v2. More feature-rich, flexible, and extensible. | Amazon Web Services
Today, AWS Amplify announces the GraphQL Transformer version 2, enabling developers to develop more feature-rich, flexible, and extensible GraphQL-based app bac...

以下の例を元に、v2に置き換えてみましょう!

type Post @model
  @key(name: "byUsername", fields: ["username"], queryField: "postsByUsername")
  @auth(rules: [
    { allow: owner, ownerField: "username" },
    { allow: public, operations: [read] }
  ]) {
  id: ID!
  title: String!
  content: String!
  username: String
}

上記は、バージョン変更前のレガシーな書き方です。

これをv2で書くと、、

type Post
  @model
  @auth(
    rules: [
      { allow: owner, ownerField: "username" }
      { allow: public, operations: [read] }
    ]
  ) {
  id: ID!
  title: String!
  content: String!
  username: String @index(name: "byUsername", queryField: "postsByUsername")
}

indexを指定したいカラムのところに記述します。

ここで指定するnameは、使われるわけではないですが、nameを指定することでindexの扱いとなります。

これにより、以下のクエリが生成されます。

export const postsByUsername = /* GraphQL */ `
  query PostsByUsername(
    $username: String
    $sortDirection: ModelSortDirection
    $filter: ModelPostFilterInput
    $limit: Int
    $nextToken: String
  ) {
    postsByUsername(
      username: $username
      sortDirection: $sortDirection
      filter: $filter
      limit: $limit
      nextToken: $nextToken
    ) {
      items {
        id
        title
        content
        username
        coverImage
        createdAt
        updatedAt
      }
      nextToken
    }
  }
`;

これで、バージョン変更前と同じクエリを作ることができました。

以上、お読みいただきありがとうございました。

コメント