AWS CLIでGSIやLSIを持つDynamoDBテーブルを作成しようとしたらハマった話

2020.07.12

こんにちは、CX事業本部の若槻です。

前回の記事ではマネジメントコンソールからGSIおよびLSIを持つDynamoDBテーブルの作成を行いました。

次に、AWS CLIでGSIやLSIを持つDynamoDBテーブルを作成しようとしたのですが、正常に作成できるまでにトライ&エラーを繰り返すハメになったので、今回はその際の記録をメモとして残させていただきます。

ハマった際の記録

GSIを持つテーブルの作成

dynamodb create-tableコマンドでglobal-secondary-indexesオプションを指定してGSIを持つテーブルを作成しようと次のようなコマンドを作成し、実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --global-secondary-indexes \
       IndexName=GSI-objectId,KeySchema=[{AttributeName=objectId,KeyType=HASH}],Projection={ProjectionType=ALL}

すると以下のエラーとなりました。

Parameter validation failed:
Invalid type for parameter GlobalSecondaryIndexes[0].KeySchema[0], value: AttributeName=objectId, type: <class 'str'>, valid types: <class 'dict'>
Invalid type for parameter GlobalSecondaryIndexes[1].KeySchema[0], value: KeyType=HASH, type: <class 'str'>, valid types: <class 'dict'>

ググって見つけたサイトによると{AttributeName=objectId,KeyType=HASH}をクォートで囲む必要があるとのことです。

そこでコマンドを次のように修正して実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --global-secondary-indexes \
       IndexName=GSI-objectId,KeySchema=[{'AttributeName=objectId,KeyType=HASH'}],Projection={ProjectionType=ALL}

すると次は以下のエラーとなりました。

An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: ProvisionedThroughput is not specified for index: GSI-objectId

global-secondary-indexesオプションでもProvisionedThroughputを指定する必要があるとのことです。GUIからGSIありのテーブルを作成した時はProvisionedThroughputを明示的に指定する必要はなかったため、CLIでも不要だと思い込んでいました。

そこでコマンドを次のように修正して実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --global-secondary-indexes \
       IndexName=GSI-objectId,KeySchema=[{'AttributeName=objectId,KeyType=HASH'}],Projection={ProjectionType=ALL},ProvisionedThroughput={ReadCapacityUnits=5,WriteCapacityUnits=5}

次は以下のようなエラーとなりました。

Parameter validation failed:
Invalid type for parameter GlobalSecondaryIndexes[0].ProvisionedThroughput, value: ReadCapacityUnits=5, type: <class 'str'>, valid types: <class 'dict'>
Invalid type for parameter GlobalSecondaryIndexes[1].ProvisionedThroughput, value: WriteCapacityUnits=5, type: <class 'str'>, valid types: <class 'dict'>

どうやらProvisionedThroughputの値もクォートで囲む必要がありそうです。

そこでコマンドを次のように修正して実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --global-secondary-indexes \
       IndexName=GSI-objectId,KeySchema=[{'AttributeName=objectId,KeyType=HASH'}],Projection={ProjectionType=ALL},ProvisionedThroughput='{ReadCapacityUnits=5,WriteCapacityUnits=5}'

次は以下のようなエラーとなりました。

An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [objectId], AttributeDefinitions: [objectType]

GSIで使用するキーもattribute-definitionsで指定する必要があるようです。

そこでコマンドを次のように修正して実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
       AttributeName=objectId,AttributeType=S \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --global-secondary-indexes \
       IndexName=GSI-objectId,KeySchema=[{'AttributeName=objectId,KeyType=HASH'}],Projection={ProjectionType=ALL},ProvisionedThroughput='{ReadCapacityUnits=5,WriteCapacityUnits=5}'

コマンドが正常に実行でき、GSIを持つテーブルを作成できました。

LSIを持つテーブルの作成

dynamodb create-tableコマンドでlocal-secondary-indexesオプションを指定してLSIを持つテーブルを作成しようと次のようなコマンドを作成し、実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
       AttributeName=updatedAt,AttributeType=N \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --local-secondary-indexes \
       IndexName=LSI-objectType,KeySchema=['{AttributeName=objectType,KeyType=HASH}','{AttributeName=updatedAt,KeyType=RANGE}'],Projection={ProjectionType=ALL}

すると以下のようなエラーとなりました。

An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Table KeySchema does not have a range key, which is required when specifying a LocalSecondaryIndex

LSIを持たせるテーブルにはプライマリソートキーを指定する必要があるようです。

そこでコマンドを次のように修正して実行しました。

$ aws dynamodb create-table \
   --table-name Object \
   --attribute-definitions \
       AttributeName=objectType,AttributeType=S \
       AttributeName=createdAt,AttributeType=N \
       AttributeName=updatedAt,AttributeType=N \
   --key-schema \
       AttributeName=objectType,KeyType=HASH \
       AttributeName=createdAt,KeyType=RANGE \
   --provisioned-throughput \
       ReadCapacityUnits=5,WriteCapacityUnits=5 \
   --local-secondary-indexes \
       IndexName=LSI-objectType,KeySchema=['{AttributeName=objectType,KeyType=HASH}','{AttributeName=updatedAt,KeyType=RANGE}'],Projection={ProjectionType=ALL}

コマンドが正常に実行でき、LSIを持つテーブルを作成できました。

GSIとLSIを持つテーブルの作成

LSIのパーティションキーに、プライマリではなくGSIのパーティションキーを指定できるのか気になったので確認してみました。

dynamodb create-tableコマンドでlocal-secondary-indexesglobal-secondary-indexesオプションを指定して、LSIとGSIを持つテーブルを作成しようと次のようなコマンドを作成し、実行しました。

$ aws dynamodb create-table \
    --table-name Object \
    --attribute-definitions \
        AttributeName=objectType,AttributeType=S \
        AttributeName=objectId,AttributeType=S \
        AttributeName=createdAt,AttributeType=N \
        AttributeName=updatedAt,AttributeType=N \
    --key-schema \
        AttributeName=objectType,KeyType=HASH \
        AttributeName=createdAt,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --global-secondary-indexes \
        IndexName=GSI-objectId,KeySchema=["{AttributeName=objectId,KeyType=HASH}"],Projection={ProjectionType=ALL},ProvisionedThroughput="{ReadCapacityUnits=5,WriteCapacityUnits=5}" \
    --local-secondary-indexes \
        IndexName=LSI-objectType,KeySchema=["{AttributeName=objectId,KeyType=HASH}","{AttributeName=updatedAt,KeyType=RANGE}"],Projection={ProjectionType=ALL}

すると次のようなエラーとなりました。

An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Index KeySchema does not have the same leading hash key as table KeySchema for index: LSI-objectType. index hash key: objectId, table hash key: objectType

LSIのパーティションキーにはプライマリと同じ属性を指定する必要があるようです。

LSIのパーティションキーにプライマリと同じ属性を指定するようにコマンドを修正し、実行してみます。

$ aws dynamodb create-table \
    --table-name Object \
    --attribute-definitions \
        AttributeName=objectType,AttributeType=S \
        AttributeName=objectId,AttributeType=S \
        AttributeName=createdAt,AttributeType=N \
        AttributeName=updatedAt,AttributeType=N \
    --key-schema \
        AttributeName=objectType,KeyType=HASH \
        AttributeName=createdAt,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --global-secondary-indexes \
        IndexName=GSI-objectId,KeySchema=["{AttributeName=objectId,KeyType=HASH}"],Projection={ProjectionType=ALL},ProvisionedThroughput="{ReadCapacityUnits=5,WriteCapacityUnits=5}" \
    --local-secondary-indexes \
        IndexName=LSI-objectType,KeySchema=["{AttributeName=objectType,KeyType=HASH}","{AttributeName=updatedAt,KeyType=RANGE}"],Projection={ProjectionType=ALL}

コマンドが正常に実行でき、テーブルを作成できました。

おわりに

AWS CLIでGSIやLSIを持つDynamoDBテーブルを作成しようとしたらハマった話のご紹介でした。

そういえば最近あまりAWS CLIを触れてなかったのでもっとちゃんと触ろうと思いました。

参考

以上