Как реализовать глобальный вторичный индекс DynamoDB с инфраструктурой как кодом в CloudFormation

Я работаю над внедрением GSI в CloudFormation с инфраструктурой как кодом. Все, что я хочу сделать, это использовать эту таблицу для подсчета записей в основной таблице DynamoTable. Вот как выглядит основная сказка:

Resources:
  CaseRecords:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:custom.tableName}
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: userId
          AttributeType: S
        - AttributeName: caseRecordId
          AttributeType: S
      KeySchema:
        - AttributeName: userId
          KeyType: HASH
        - AttributeName: caseRecordId
          KeyType: RANGE

Мне не нужны ключи из исходной таблицы, и все, что я хочу, это создать новый HASH-ключ для нового GSI, который сообщит мне, из какой таблицы был взят счет, который я отслеживаю, т. е. из приведенной выше таблицы.

Ниже показано, как я пытался реализовать GSI:

# Implement a GSI to handle item count totals
      GlobalSecondaryIndexes:
          - IndexName: gsiCaseCountTable
            KeySchema: 
              - AttributeName: table-name
                KeyType: HASH
            ProvisionedThroughput:
              ReadCapacityUnits: 5
              WriteCapacityUnits: 5

Однако ошибка, которую я получаю, выглядит следующим образом:

An error occurred: CaseRecords - Property Projection cannot be empty..

Когда я включаю PROJECTION, который у меня был, только userId из исходной таблицы просто для отслеживания количества записей в исходной таблице для каждого пользователя, я пробую следующее:

 Implement a GSI to handle item count totals
      GlobalSecondaryIndexes:
      - IndexName: gsiCaseCountTable
        KeySchema:
        - AttributeName: table-name
          KeyType: HASH
        Projection:
          NonKeyAttributes:
          - userId
          ProjectionType: INCLUDE
        ProvisionedThroughput:
          ReadCapacityUnits: 5
          WriteCapacityUnits: 5

Однако это также возвращает ошибку:

An error occurred: CaseRecords - Property AttributeDefinitions is inconsistent with the KeySchema of the table and the secondary indexes.

Как я могу правильно реализовать глобальный вторичный индекс в Dynamo с помощью шаблона CloudFormation, чтобы я мог записывать количество записей в исходной таблице????

Спасибо.

ОБНОВЛЕНИЕ

Если кому-то интересно, вот как я смог его развернуть. Это не идеальное решение, но оно позволяет мне отслеживать и подсчитывать записи в таблице элементов:

# NOTE: DynamoDB Serverless Configuration
# NoSQL Table for CaseRecord DB

Resources:
  CaseRecords:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:custom.tableName}
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: userId
          AttributeType: S
        - AttributeName: caseRecordId
          AttributeType: S
      KeySchema:
        - AttributeName: userId
          KeyType: HASH
        - AttributeName: caseRecordId
          KeyType: RANGE
      # Set the capacity based on the stage
      # ProvisionedThroughput:
        # ReadCapacityUnits: ${self:custom.tableThroughput}
        # WriteCapacityUnits: ${self:custom.tableThroughput}
      # Implement a GSI to handle item count totals
      GlobalSecondaryIndexes:
      - IndexName: gsiCaseCountTable
        KeySchema:
        - AttributeName: userId
          KeyType: HASH
        Projection:
          ProjectionType: KEYS_ONLY

ОБНОВЛЕНИЕ № 2 – НЕ ПРОШЕЛ

Основываясь на информации, предоставленной @Pedro Arantes ниже, я пытаюсь реализовать GSI с определениями атрибутов, которые я хочу использовать. Это тоже, однако, терпит неудачу. Ниже приведена реализация, а вот ссылка на документ AWS, который я использовал: AWS GSI Doc и вот неудачная реализация:

Resources:
  CaseRecords:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:custom.tableName}
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: userId
          AttributeType: S
        - AttributeName: caseRecordId
          AttributeType: S
        - AttributeName: table-name
          AttributeType: S
        - AttributeName: count
          AttributeType: N
      KeySchema:
        - AttributeName: userId
          KeyType: HASH
        - AttributeName: caseRecordId
          KeyType: RANGE
      # Set the capacity based on the stage
      # ProvisionedThroughput:
        # ReadCapacityUnits: ${self:custom.tableThroughput}
        # WriteCapacityUnits: ${self:custom.tableThroughput}
      # Implement a GSI to handle item count totals
      GlobalSecondaryIndexes:
      - IndexName: gsiCaseCountTable
        KeySchema:
        - AttributeName: table-name
          KeyType: HASH
        Projection: 
          NonKeyAttributes: 
            - userId
            - count
          ProjectionType: INCLUDE

Как я могу заставить это работать только с NonKeyAttributes, которые я объявил в AttributeDefinitions???


person lopezdp    schedule 14.06.2019    source источник


Ответы (1)


Вам нужно добавить table-name в свойство AttributeDefinitions. Из документов< /а>:

Определения атрибутов

Список атрибутов, описывающих схему ключей для таблицы и индексов. Допускаются дубликаты.

Таким образом, даже если вы не используете какой-либо атрибут в исходной таблице, вы должны объявить, что можете использовать его в своих GSI.

ОБНОВЛЕНИЕ № 2 – НЕ ПРОШЕЛ

Вы используете атрибуты ключей userId и count, которые вы определили в AttributeDefinitions как NonKeyAttributes (но они являются атрибутами ключей) в Projection. Вам не нужно добавлять их, потому что они проецируются автоматически. Из документов< /а>:

AWS::DynamoDB::Проекция таблицы

Представляет атрибуты, которые копируются (проецируются) из таблицы в индекс. Это дополнение к атрибутам первичного ключа и атрибутам ключа индекса, которые проецируются автоматически.

КОНЕЧНЫЙ ШАБЛОН

Resources:
  CaseRecords:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: ${self:custom.tableName}
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: userId
          AttributeType: S
        - AttributeName: caseRecordId
          AttributeType: S
        - AttributeName: table-name
          AttributeType: S
      KeySchema:
        - AttributeName: userId
          KeyType: HASH
        - AttributeName: caseRecordId
          KeyType: RANGE
      # Set the capacity based on the stage
      # ProvisionedThroughput:
      # ReadCapacityUnits: ${self:custom.tableThroughput}
      # WriteCapacityUnits: ${self:custom.tableThroughput}
      # Implement a GSI to handle item count totals
      GlobalSecondaryIndexes:
        - IndexName: gsiCaseCountTable
          KeySchema:
            - AttributeName: table-name
              KeyType: HASH
          Projection:
            NonKeyAttributes:
              - count
            ProjectionType: INCLUDE

Соображения:

  1. count не должно быть на AttributeDefinitions, потому что вы не используете его в качестве ключа.

  2. Вам не нужно добавлять userId в Projection, потому что это будет проект автоматически, так как он определен в AttributeDefinitions.

person Pedro Arantes    schedule 14.06.2019
comment
Итак, если я хочу указать поле, которое только увеличивает счетчик, должен ли я включать его в качестве атрибута в исходную таблицу? Теперь я беспокоюсь, что реализация, которую я завершил выше, теперь дублирует поля. - person lopezdp; 14.06.2019
comment
Вы добавляете атрибуты ключей count и userId как NonKeyAttributes - person Pedro Arantes; 14.06.2019
comment
Вот сообщение об ОШИБКЕ: Произошла ошибка: CaseRecords - Property AttributeDefinitions несовместим с KeySchema таблицы и вторичных индексов. - person lopezdp; 14.06.2019
comment
Я пытаюсь получить ключ HASH с именем table-name, который я буду использовать только в GSI. Я добавил его в AttributeDefinitions, чтобы использовать его в GSI. Это единственный ключ, который мне нужен. Оттуда я действительно просто хочу, чтобы userId считался обычными полями, не являясь ключами... Где я здесь ошибаюсь? - person lopezdp; 14.06.2019
comment
Давайте продолжим обсуждение в чате. - person Pedro Arantes; 14.06.2019