键模式中的属性数必须与属性定义中定义的属性数匹配

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)。这是异常的根本原因。

【讨论】:

我相信有一个例外,如果该键将用作索引中的hashrange 键,则非键属性应位于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 中声明属性

当这些属性将在GlobalSecondaryIndexesLocalSecondaryIndexes 中使用时

对于任何使用 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),如果您也有 GlobalSecondaryIndexesLocalSecondaryIndexes,那么您的 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,而不是空的。

【讨论】:

以上是关于键模式中的属性数必须与属性定义中定义的属性数匹配的主要内容,如果未能解决你的问题,请参考以下文章

如何在Java类中定义接口属性并如何使用接口的方法

为多个 vue 属性重用 apollo graphql 查询定义

010. CSS 选择器

数组定义属性遍历循环,输出最大数

如何在 Ember 模型单元测试中检查属性属性类型?

Vue路由匹配规则routes中的name属性