UnknownPerson
UnknownPerson

Reputation: 184

Serverless error in dynamo get ValidationException: The provided key element does not match the schema

I'm using serverless to create and query a DynamoDB database table, but when not querying using the primary key I get this error:

INFO Error in dynamo get ValidationException: The provided key element does not match the schema

I have another key setup as a GSI, but I still get the error.

serverless.yml

...

resources:
  Resources:
    BeaconTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: venue-table
        AttributeDefinitions:
          - AttributeName: VenueID
            AttributeType: S
        KeySchema:
          - AttributeName: VenueID
            KeyType: HASH
        BillingMode: PAY_PER_REQUEST

Dynamo.js

const AWS = require('aws-sdk');

const documentClient = new AWS.DynamoDB.DocumentClient();

const Dynamo = {
    async get(TableName){
        const params = {
            TableName,
            Key:{
                "BeaconAddr": <string> // Hardcoded string
            }
        };

        const data = await documentClient
            .get(params)
            .promise()

        if (!data || !data.Item){
            throw Error(`There was an error fetching the data for ID of ${ID} from ${TableName}`)
        }
        console.log(data);

        return data;
    },

    async write(data, TableName){
        if (!data.ID){
            throw Error('no ID on the data');
        }

        const params = {
            TableName,
            Item: data
        };

        const res = await documentClient.put(params).promise();

        if (!res) {
            throw Error(`There was an error inserting ID of ${data.ID} in table ${TableName}`)
        }

        return data;
    }

};

module.exports = Dynamo;

The query works when the key is "VenueID", but when I change it to "BeaconAddr" (Which is a GSI) the error appears. What am I doing wrong?

Below is a diagram of the table:

Diagram of Table

Upvotes: 0

Views: 376

Answers (1)

Jason Wadsworth
Jason Wadsworth

Reputation: 8885

A get operation in DynamoDB is only available on the primary key of the table. Your table definition (as shown in the serverless.yml) only includes a partition key (aka HASH), so the only way to use the get operation is to request a single item by the key (which you have named VenueID). If your intent is to have the sort key (aka RANGE) be the SK attribute, and the partition key be the PK attribute, then your table definition needs to look something like this:

    BeaconTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: venue-table
        AttributeDefinitions:
          - AttributeName: PK
            AttributeType: S
          - AttributeName: SK
            AttributeType: S
        KeySchema:
          - AttributeName: PK
            KeyType: HASH
          - AttributeName: SK
            KeyType: RANGE
        BillingMode: PAY_PER_REQUEST

Note that there is no mention of VenueID or BeaconAddr in the definition. You would put the values, as you have in the display above, into those fields. To add a GSI, as you have displayed, you'd need to have this:

    BeaconTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: venue-table
        AttributeDefinitions:
          - AttributeName: PK
            AttributeType: S
          - AttributeName: SK
            AttributeType: S
          - AttributeName: GSI-1-PK
            AttributeType: S
          - AttributeName: GSI-1-SK
            AttributeType: S
        KeySchema:
          - AttributeName: PK
            KeyType: HASH
          - AttributeName: SK
            KeyType: RANGE
        GlobalSecondaryIndexes:
          - IndexName: GSI-1
            KeySchema: 
              - AttributeName: "GSI-1-PK"
                KeyType: HASH
              - AttributeName: GSI-1-SK
                KeyType: RANGE
        BillingMode: PAY_PER_REQUEST

Note that there are separate columns here. The data that goes into those columns is up to you to populate.

Finally, when querying a GSI (you cannot get on a GSI) you must supply the index name in the query.

Upvotes: 2

Related Questions