I have an AWS DynamoDb table called AccountXX which stores items with a JSON structure as:

{
  "id": "some id value", // also the partition key for the table
  "name": "a name",
  "email": "an email address",
  "salt": [12, 3, ... ], // an array of random values
  "hash": [1, 5, ... ],  // an array representing a hashed password
  ... // and some more attributes
}

There is a Global Secondary Index named Account_email_hash_salt_gsi on the AccountXX table which has the partition key email and has the additional attributes hash, salt and id.

When I issue the following AWS CLI command, I am able to query an item in the table successfully:

aws dynamodb query --table AccountXX 
  --index-name Account_email_hash_salt_gsi 
  --key-condition-expression "email = :emailValue" 
  --expression-attribute-values file://values.json

The contents of values.json is:

{":emailValue":{"S": "[email protected]"}}

However, when I issue an analogous call using AWS.DynamoDB.DocumentClient instance using the following parameter object, I get an error:

  const params = {
    TableName: accountTable,       // will be set to 'AccountXX'
    IndexName: "Account_email_hash_salt_gsi",
    KeyConditionExpression:"#email = :emailValue",
    ExpressionAttributeNames: {
        "#email": "email"
    },
    ExpressionAttributeValues: {
        ":emailValue": {"S": loginToken.email}
    },
    ScanIndexForward: false
  };

The error I get is:

ValidationException: One or more parameter values were invalid: Condition parameter type does not match schema type
    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:52:27)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)

I also tried using a modified parameter object as follows:

  const params = {
    TableName: accountTable,   // will be set to 'AccountXX'
    IndexName: "Account_email_hash_salt_gsi",
    KeyConditionExpression:"#email = :emailValue",
    ExpressionAttributeNames: {
        "#email": "email"
    },
    ExpressionAttributeValues: {
        ":emailValue": loginToken.email   // directly using string type
    },
    ScanIndexForward: false
  };

In this case, I got the following error:

ValidationException: ExpressionAttributeValues must not be empty
    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:52:27)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)

In both cases, my DynamoDB DocumentClient query is issued as:

const data = await dynamo.query(params).promise();

What should I do to fix the params object so that I am able to query the table successfully?

1

There are 1 best solutions below

0
On BEST ANSWER

Found and fixed the problem. The issue was not with the DynamoDB query or parameters construct. The root cause was the problem with the Lambda passing the POST request body and the handler incorrectly handling it. The handler was missing a JSON.parse(event.body) and hence loginToken was a string. Therefore loginToken.email was evaluating to empty causing the query to fail.

BTW, I found Amazon NoSQL Workbench tool that was mentioned in an answer to another similar question to be very helpful in exploring queries and autogenerating them using the UI. I used that to ensure that the query parameters were syntactically correct and then was able to find the root cause after some troubleshooting.