主键模式中的属性数量必须与属性定义中定义的属性数量相匹配。

212

我正在尝试使用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 上吗?当您尝试针对实际服务执行相同操作时会发生什么? - mkobit
1
我还没有AWS账户,所以无法对实际服务进行测试。我正在使用最新版本的DynamoDB本地版(dynamodb_local_2015-04-27_1.0)。 - NAbbas
2
我在使用dynamodb_local_2016-04-19时遇到了相同的问题。 - Chris
2
没关系,明亮的 TL;DR 已经说得很清楚了。 - Chris
6个回答

458

TL;DR 不要在AttributeDefinitions中包含任何非键属性定义。

DynamoDB是无模式的(除了键模式)

也就是说,当您创建表时,需要指定键模式(属性名称和类型)。但是,您不需要指定任何非键属性。稍后可以放置具有任何属性的项目(当然必须包括键)。

文档页面可知,AttributeDefinitions被定义为:

描述表和索引的键模式的属性数组。

创建表时,AttributeDefinitions字段仅用于哈希和/或范围键。在第一种情况下,只提供哈希键(数字1),而您提供了2个AttributeDefinitions。这是异常的根本原因。


18
除了一个例外,我认为非关键属性应该在AttributeDefinitions中,如果该键将用作索引的hashrange键。 - Srle
如果这是真的,那么我如何添加一个不在索引中的TTL字段? - Ryan
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#cfn-dynamodb-table-timetolivespecification - Mike DeMille

38
当您在 "AttributeDefinitions" 中使用非关键属性时,必须将其用作索引,否则这与 DynamoDB 的工作方式相违背。请参见链接。 因此,如果你不打算将非关键属性用作索引或主键,则无需把它放在 "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
        });```

9

只有在将属性用于KeySchemaGlobalSecondaryIndexesLocalSecondaryIndexes时,才在AttrubuteDefinitions中声明属性。

对于使用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:

如果你同时拥有GlobalSecondaryIndexes或者LocalSecondaryIndexes,并且它们具有相同的属性(即id、status和createdAt),那么你的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中包含了状态和createdId,这是因为我们有一个使用上述属性的GlobalSecondaryIndex。

原因:DynamoDB只关心主键、全局二级索引和本地二级索引。您无需指定任何不属于上述三元组的其他类型的属性。

DynamoDB仅关心用于分区的主键、全局二级索引和本地二级索引。它不关心您拥有哪些其他项目属性。


2

在创建表时,不要在--attribute-definitions--key-schema中包含所有的键值。只需在其中包含HASH和RANGE键。

当您向Dynamo插入项目时,它也会接受上述属性/模式中未定义的其他键。

例如:

创建表:

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

现在你可以插入一个包含其他键的项目,只需要在项目中存在idsid即可。

1
我也遇到了这个问题,如果有帮助的话,我会在这里发布我所遇到的问题。
在我的 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,而不是空的。

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接