In Amazon DynamoDB, an item is a collection of attributes. Each attribute has a name and a value. An attribute value can be a scalar, a set, or a document type. For more information, see Amazon DynamoDB: How it works. DynamoDB provides four operations for basic create, read, update, and delete (CRUD) functionality.
A key schema specifies the attributes that make up the primary key of a table, or the key attributes of an index. A KeySchemaElement represents exactly one attribute of the primary key. For example, a simple primary key would be represented by one KeySchemaElement (for the partition key).
There is no limit to the number of attributes but the total item size is limited to 400kb. The maximum item size in DynamoDB is 400 KB, which includes both attribute name binary length (UTF-8 length) and attribute value lengths (again binary length). The attribute name counts towards the size limit.
The term "range attribute" derives from the way DynamoDB stores items with the same partition key physically close together, in sorted order by the sort key value. For a simple primary key (partition key), you must provide exactly one element with a KeyType of HASH .
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.
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
});```
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With