键模式中的属性数必须与属性定义中定义的属性数匹配
Posted
技术标签:
【中文标题】键模式中的属性数必须与属性定义中定义的属性数匹配【英文标题】:Number of attributes in key schema must match the number of attributes defined in attribute definitions 【发布时间】:2015-09-01 04:19:21 【问题描述】:我正在尝试使用 DynamoDB javascript shell 创建一个简单的表,但遇到了这个异常:
"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
下面是我要创建的表:
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);
);
但是,如果我将第二个属性添加到 KeySchema
,它就可以正常工作。工作台下方:
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);
);
我不想将范围添加到键模式。知道如何解决吗?
【问题讨论】:
这只发生在 DynamoDBLocal 上吗?当您尝试对实际服务执行相同操作时会发生什么? 我还没有 AWS 账户,所以无法针对实际服务进行测试。我正在使用最新版本的本地 DynamoDB (dynamodb_local_2015-04-27_1.0)。 我遇到了与 dynamodb_local_2016-04-19 相同的行为 没关系,明亮的 TL;DR 说明了一切。 【参考方案1】:TL;DR 不要在AttributeDefinitions
中包含任何非关键属性定义。
DynamoDB 是无模式的(关键模式除外)
也就是说,您确实需要在创建表时指定键模式(属性名称和类型)。好吧,您不需要指定任何非关键属性。您可以稍后放置具有任何属性的项目(当然必须包括键)。
从documentation page,AttributeDefinitions
定义为:
描述表和索引的键模式的属性数组。
创建表时,AttributeDefinitions
字段仅用于哈希和/或范围键。在您的第一种情况下,当您提供 2 个 AttributeDefinitions 时,只有哈希键(数字 1)。这是异常的根本原因。
【讨论】:
我相信有一个例外,如果该键将用作索引中的hash
或range
键,则非键属性应位于AttributeDefinitions
中
如果这是真的那么我如何添加一个不在索引中的 TTL 字段?
docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/…【参考方案2】:
当您在"AttributeDefinitions"
使用非键属性时,必须将其用作索引,否则不利于 DynamoDB 的工作方式。见the link。
因此,如果您不打算将其用作索引或主键,则无需在 "AttributeDefinitions"
中添加非键属性。
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
);```
【讨论】:
【参考方案3】:仅当您要使用KeySchema
中的属性时,才在AttrubuteDefinitions
中声明属性
或
当这些属性将在GlobalSecondaryIndexes
或LocalSecondaryIndexes
中使用时
对于任何使用 yaml 文件的人:
示例 1:
假设你有 3 个属性 -> id、status、createdAt。
这里的 id 是KeySchema
AuctionsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: AuctionsTable
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
示例2:
对于相同的属性(即 id、status 和 createdAt),如果您也有 GlobalSecondaryIndexes
或 LocalSecondaryIndexes
,那么您的 yaml 文件如下所示:
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
我们在 AttributeDefinitions 中包含 status 和 createdId 只是因为我们有一个使用上述属性的 GlobalSecondaryIndex
。
原因:DynamoDB 只关心主键、GlobalSecondaryIndex 和 LocalSecondaryIndex。您无需指定不属于上述三重奏的任何其他类型的属性。
DynamoDB 只关心 Primary Key、GlobalSecondaryIndex 和 LocalSecondaryIndex 进行分区。它不关心你对一个项目还有什么其他属性。
【讨论】:
【参考方案4】:我也遇到了这个问题,我会在这里发布对我来说出了什么问题,以防它帮助其他人。
在我的CreateTableRequest
中,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>
//
//
;
在表创建中注释掉这些行解决了我的问题。所以我猜这个列表必须是null
,而不是空的。
【讨论】:
以上是关于键模式中的属性数必须与属性定义中定义的属性数匹配的主要内容,如果未能解决你的问题,请参考以下文章