Adding indexes to DynamoDB with AWS Amplify


Using AWS Amplify and specifically the Amplify CLI makes it easy to create a GraphQL API backed by DynamoDB for persistance. Stepping through the CLI questions allows the CloudFormation to be generated for you and the stack to be deployed or updated easily. It will also create the necessary resolvers for AppSync and allow you to define models in the GraphQL schema which are the basis for the DynamoDB tables.

An issue I ran across however was adding an index to the table using the @key directive as in the documentation after the initial creation of the table. I initially created the following model for a transaction.

type Transaction @model {
  id: ID!
  accountId: ID!
  type: TransactionType!
  notes: String
  amount: Int!
}

enum TransactionType {
  WITHDRAWAL
  DEPOSIT
}

Later I decided that it would be useful to query based on accountId and createdAt datetime. I modified the Transaction type as below and attempted to push through the Amplify CLI (amplify push). FYI the createdAt field is already on the auto-created DynamoDB table but you can add it to your schema if you need to retrieve the values.

type Transaction @model @key(fields: ["accountId", "createdAt"]) {
  id: ID!
  accountId: ID!
  type: TransactionType!
  notes: String
  amount: Int!
  createdAt: String!
}

All seemed well until the push tries to continue and the following error pops out.

Attempting to edit the key schema of the TransactionTable table in the Transaction stack. An error occured during the push operation: Attempting to edit the key schema of the TransactionTable table in the Transaction stack.

Unfortunately the error isn’t terribly descriptive however Amplify has a useful tool that is better at checking the schema and providing more information, namely amplify api gql-compile. This gives us a much more informative error message.

Attempting to edit the key schema of the TransactionTable table in the Transaction stack. Cause: Adding a primary @key directive to an existing @model. How to fix: Remove the @key directive or provide a name e.g @key(name: "ByStatus", fields: ["status"]).

So that’s a lot more useful and informative showing that we’re trying to change the existing table (and it’s likely complaining as it would affect the primary partition key). So instead let’s name it as the error directs us to “ByAccountByCreatedAt” as below. One extra property called queryField allows us to use this as a query operation and Amplify will automatically update our queries.js file if we allow it.

type Transaction
  @model
  @key(
    name: "ByAccountByCreatedAt"
    fields: ["accountId", "createdAt"]
    queryField: "transactionsByAccountByCreatedAt"
  ) {
  id: ID!
  accountId: ID!
  type: TransactionType!
  notes: String
  amount: Int!
  createdAt: String!
}

When we try the gql-compile command again it compiles successfully and we can try to push it again to make the changes. After that’s run we can look in the AWS Console and see that we now have a Global Secondary Index created based on the @key directive allowing us to query. We can test it in the AppSync console by passing in an accountId value and a createdAt condition (e.g. eq, ge, beginsWith, etc.)

query MyQuery {
  transactionsByAccountByCreatedAt(
    accountId: "account1"
    createdAt: { ge: "2020" }
  ) {
    items {
      accountId
      amount
      createdAt
      id
      notes
      type
    }
  }
}