Number of attributes in key schema must match the number of attributes defined in attribute definitions
Asked Answered
L

6

217

I’m trying to create a simple table using DynamoDB JavaScript shell and I’m getting this exception:

{
  "message": "The number of attributes in key schema must match the number of attributes defined in attribute definitions.",
  "code": "ValidationException",
  "time": "2015-06-16T10:24:23.319Z",
  "statusCode": 400,
  "retryable": false
}

Below is the table I’m trying to create:

var params = {
  TableName: 'table_name',
  KeySchema: [
    {
      AttributeName: 'hash_key_attribute_name',
      KeyType: 'HASH'
    }
  ],
  AttributeDefinitions: [
    {
      AttributeName: 'hash_key_attribute_name',
      AttributeType: 'S'
    },
    {
      AttributeName: 'attribute_name_1',
      AttributeType: 'S'
    }
  ],
  ProvisionedThroughput: {
    ReadCapacityUnits: 1,
    WriteCapacityUnits: 1
  }
};
dynamodb.createTable(params, function(err, data) {
  if (err) print(err);
  else print(data);
});

However if I add the second attribute to the KeySchema, it works fine. Below a the working table:

var params = {
  TableName: 'table_name',
  KeySchema: [
    {
      AttributeName: 'hash_key_attribute_name',
      KeyType: 'HASH'
    },
    {
      AttributeName: 'attribute_name_1',
      KeyType: 'RANGE'
    }
  ],
  AttributeDefinitions: [
    {
      AttributeName: 'hash_key_attribute_name',
      AttributeType: 'S'
    },
    {
      AttributeName: 'attribute_name_1',
      AttributeType: 'S'
    }
  ],
  ProvisionedThroughput: {
    ReadCapacityUnits: 1,
    WriteCapacityUnits: 1
  }
};
dynamodb.createTable(params, function(err, data) {
  if (err) print(err);
  else print(data);
});

I don’t want to add the range to key schema. Any idea how to fix it?

Lobeline answered 16/6, 2015 at 11:15 Comment(4)
Does this only happen against DynamoDBLocal? What happens when you try to do the same thing against the actual service?Ludmilla
I don't have a AWS account yet, so couldn't test it against actual service. I'm using the latest version of DynamoDB local (dynamodb_local_2015-04-27_1.0).Lobeline
I'm experiencing the same behavior with dynamodb_local_2016-04-19Rushing
Nevermind, Mingliang's TL;DR says it all.Rushing
A
466

TL;DR Don't include any non-key attribute definitions in AttributeDefinitions.

DynamoDB is schemaless (except the key schema)

That is to say, you do need to specify the key schema (attribute name and type) when you create the table. Well, you don't need to specify any non-key attributes. You can put an item with any attribute later (must include the keys of course).

From the documentation page, the AttributeDefinitions is defined as:

An array of attributes that describe the key schema for the table and indexes.

When you create table, the AttributeDefinitions field is used for the hash and/or range keys only. In your first case, there is hash key only (number 1) while you provide 2 AttributeDefinitions. This is the root cause of the exception.

Archiphoneme answered 18/6, 2015 at 19:44 Comment(3)
with one exception i believe, non-key attribute should be in AttributeDefinitions if that key will be used as hash or range key in indexHesperus
if this is true then how do I add a TTL field which is not in an index?Unbridle
docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…Sped
D
38

When you use non-key attribute in at "AttributeDefinitions", you must use it as index, otherwise it's against the way of DynamoDB to work. See the link.

So no need to put a non-key attribute in "AttributeDefinitions" if you're not gonna use it as index or primary key.

    var params = {
            TableName: 'table_name',
            KeySchema: [ // The type of of schema.  Must start with a HASH type, with an optional second RANGE.
                { // Required HASH type attribute
                    AttributeName: 'UserId',
                    KeyType: 'HASH',
                },
                { // Optional RANGE key type for HASH + RANGE tables
                    AttributeName: 'RemindTime', 
                    KeyType: 'RANGE', 
                }
            ],
            AttributeDefinitions: [ // The names and types of all primary and index key attributes only
                {
                    AttributeName: 'UserId',
                    AttributeType: 'S', // (S | N | B) for string, number, binary
                },
                {
                    AttributeName: 'RemindTime',
                    AttributeType: 'S', // (S | N | B) for string, number, binary
                },
                {
                    AttributeName: 'AlarmId',
                    AttributeType: 'S', // (S | N | B) for string, number, binary
                },
                // ... more attributes ...
            ],
            ProvisionedThroughput: { // required provisioned throughput for the table
                ReadCapacityUnits: 1, 
                WriteCapacityUnits: 1, 
            },
            LocalSecondaryIndexes: [ // optional (list of LocalSecondaryIndex)
                { 
                    IndexName: 'index_UserId_AlarmId',
                    KeySchema: [ 
                        { // Required HASH type attribute - must match the table's HASH key attribute name
                            AttributeName: 'UserId',
                            KeyType: 'HASH',
                        },
                        { // alternate RANGE key attribute for the secondary index
                            AttributeName: 'AlarmId', 
                            KeyType: 'RANGE', 
                        }
                    ],
                    Projection: { // required
                        ProjectionType: 'ALL', // (ALL | KEYS_ONLY | INCLUDE)
                    },
                },
                // ... more local secondary indexes ...
            ],
        };
        dynamodb.createTable(params, function(err, data) {
            if (err) ppJson(err); // an error occurred
            else ppJson(data); // successful response
        });```
Demasculinize answered 29/8, 2016 at 13:30 Comment(0)
N
9

Declare attributes in AttrubuteDefinitions only if you are going to use the attribute in KeySchema

OR

when those attributes are going to be used in GlobalSecondaryIndexes or LocalSecondaryIndexes

For anybody using yaml files:

Example 1:

Lets say you have 3 attributes -> id, status, createdAt. Here id is the KeySchema

    AuctionsTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: AuctionsTable
        BillingMode: PAY_PER_REQUEST
        
        AttributeDefinitions:
          - AttributeName: id
            AttributeType: S

        KeySchema:
          - AttributeName: id 
            KeyType: HASH

Example2:

For the same attributes(ie. id, status and createdAt) if you have GlobalSecondaryIndexes or LocalSecondaryIndexes as well, then your yaml file looks like:

AuctionsTable:
  Type: AWS::DynamoDB::Table
  Properties:
    TableName: AuctionsTable-${self:provider.stage}
    BillingMode: PAY_PER_REQUEST
    AttributeDefinitions:
      - AttributeName: id
        AttributeType: S
      - AttributeName: status
        AttributeType: S
      - AttributeName: endingAt
        AttributeType: S
    KeySchema:
      - AttributeName: id
        KeyType: HASH
    GlobalSecondaryIndexes:
      - IndexName: statusAndEndDate
        KeySchema:
          - AttributeName: status
            KeyType: HASH
          - AttributeName: endingAt
            KeyType: RANGE
        Projection:
          ProjectionType: ALL

We have included status and createdId in AttributeDefinitions only because we have a GlobalSecondaryIndex which uses the aforementioned attributes.

Reason: DynamoDB only cares about the Primary Key, GlobalSecondaryIndex and LocalSecondaryIndex. You don't need to specify any other types of attributes which are not part of the above mentioned trio.

DynamoDB is only concerned with Primary Key, GlobalSecondaryIndex and LocalSecondaryIndex for partitioning. It doesn't care what other attributes you have for an item.

Nelan answered 29/5, 2021 at 13:58 Comment(0)
C
2

Do not include all the Key values in the --attribute-definitions and --key-schema. Only include the HASH and RANGE keys in these while creating table.

When you are inserting an item into dynamo, it will accept other keys too that were no defined in the above attributes/schema.

for example:

Creating table:

aws dynamodb create-table \
    --table-name Orders \
    --attribute-definitions \
        AttributeName=id,AttributeType=S \
        AttributeName=sid,AttributeType=S \
    --key-schema \
        AttributeName=id,KeyType=HASH \
        AttributeName=sid,KeyType=RANGE \
    --provisioned-throughput \
        ReadCapacityUnits=5,WriteCapacityUnits=5 \
    --endpoint-url=http://localhost:4566

and now you can insert an item containing other keys too, just id and sid have to be present in the item

Culture answered 11/5, 2022 at 9:11 Comment(0)
M
2

DynamoDB is schemaless: When you create a table in DynamoDB, you specify only the primary key attributes, such as partition key or partition key and sort key. You do not define any other attributes in advance.

https://aws.amazon.com/blogs/database/should-your-dynamodb-table-be-normalized-or-denormalized/#:~:text=DynamoDB%20is%20schemaless%3A%20When%20you,access%20for%20internet%2Dscale%20applications.

Menedez answered 10/10, 2023 at 19:59 Comment(0)
T
1

I also had this problem and I'll post here what went wrong for me in case it helps someone else.

In my CreateTableRequest, I had an empty array for the GlobalSecondaryIndexes.

 CreateTableRequest createTableRequest = new CreateTableRequest
 {
   TableName = TableName,
   ProvisionedThroughput = new ProvisionedThroughput { ReadCapacityUnits = 2, WriteCapacityUnits = 2 },
   KeySchema = new List<KeySchemaElement>
   {
      new KeySchemaElement
      {
         AttributeName = "Field1",
         KeyType = KeyType.HASH
      },
      new KeySchemaElement
      {
         AttributeName = "Field2",
         KeyType = KeyType.RANGE
      }
   },
   AttributeDefinitions = new List<AttributeDefinition>()
   {
      new AttributeDefinition
      {
          AttributeName = "Field1", 
          AttributeType = ScalarAttributeType.S
      },
      new AttributeDefinition
      {
         AttributeName = "Field2",
         AttributeType = ScalarAttributeType.S
      }
   },
   //GlobalSecondaryIndexes = new List<GlobalSecondaryIndex>
   //{                            
   //}
 }; 

Commenting out these lines in the table creation solved my problem. So I guess the list has to be null, not empty.

Translator answered 26/5, 2016 at 13:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.