30
votes

I'm just getting started using DynamoDB and have setup an 'accounts' table.

I've set-up a secondary index so I can query an api user and user key. Neither of these values are the primary key, as they are both volatile and can be changed.

The Table is built with

TableName: "Accounts",
        KeySchema:  [
            { AttributeName: "id", KeyType: "HASH" },
            { AttributeName: "email", KeyType: "RANGE" }
        ],
        AttributeDefinitions: [
            { AttributeName: "id", AttributeType: "S" },
            { AttributeName: "email", AttributeType: "S" }
        ]

And the Index is

 TableName: 'Accounts',
            AttributeDefinitions: [
                {AttributeName: 'name', AttributeType: 'S'},
                {AttributeName: 'apiKey', AttributeType: 'S'}
            ],
            GlobalSecondaryIndexUpdates: [
                {
                    Create: {
                        IndexName: "ApiAccounts",
                        ProvisionedThroughput: {
                            ReadCapacityUnits: 1, WriteCapacityUnits: 1
                        },
                        KeySchema: [
                            {AttributeName: 'name', KeyType: "HASH"},
                            {AttributeName: 'apiKey', KeyType: "STRING"} 
                        ],
                        Projection: {
                            ProjectionType: "KEYS_ONLY"
                        },

I'm now trying to get a uses account by querying the ApiAccounts index.

I'm trying

 dynamoClient.get({
            TableName: 'Accounts',
            IndexName: 'ApiAccounts',
            Key: {
                name: nameKeyArray[0],
                apiKey: nameKeyArray[1]
            }, callback)

But I am getting an error One of the required keys was not given a value, which leads me to believe I can't do a 'get' on a Index? Or I'm not referring the index properly. Can somebody clarify for me?

Name and API Key are unique, so I think I want to avoid a query or scan if possible

1

1 Answers

59
votes

I guess its not so clear from the official docs. You may perform Scan or Query operation on GSI index, but not the GetItem operation.

For every record / item in a Table, they must have unique HASH and RANGE keys.

i.e.

// assume dummy api putItem(id, email, name, apiKey)
account.putItem("1", "[email protected]", "john", "key1") // OK
account.putItem("1", "[email protected]", "john", "key1") // NOT OK, id and email are table HASH and RANGE keys, must be unique

But for Index'es, Hash and Range keys are not unique, they may contain duplicated records / items.

i.e.

// assume dummy api putItem(id, email, name, apiKey)
account.putItem("1", "[email protected]", "john", "key1") // OK
account.putItem("1", "[email protected]", "john", "key1") // OK

i.e.

// assume dummy api putItem(id, email, name, apiKey)
account.putItem("1", "[email protected]", "john", "key1") // OK
account.putItem("2", "[email protected]", "john", "key1") // OK

Java

http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/Index.html

Index implements QueryApi and ScanApi but not GetItemApi.

JavaScript

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#getItem-property

GetItem does not accept IndexName as a parameter.

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#query-property

Query accepts IndexName as a parameter.

http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB.html#scan-property

Scan accepts IndexName as a parameter.