I am developing an AWS service using the Serverless Framework. So far it has one table and a couple global secondary indexes. I'm trying to query against a global secondary index.
Query:
{
"TableName": "messages-table-dev",
"IndexName": "roomIndex",
"KeyConditionExpression": "room = :room",
"ExpressionAttributeValues": {
":room": {
"S": "everyone"
}
}
}
It gives an exception -- using the Node.js DynamoDB client, not the Node.js DocumentClient
ValidationException: One or more parameter values were invalid: Condition parameter type does not match schema type
at Request.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:48:27)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
message: 'One or more parameter values were invalid: Condition parameter type does not match schema type',
code: 'ValidationException',
time: 2018-06-05T05:11:08.899Z,
requestId: '72OROVKI35I3QDO2IJNQH6SIRVVV4KQNSO5AEMVJF66Q9ASUAAJG',
statusCode: 400,
retryable: false,
retryDelay: 35.265782751506215
I understand from the documentation that KeyConditionExpression must do an equality match on the partition index. In this case the room
field is the partition index of the roomIndex
global secondary index. According to the documentation, you substitute values into the expression using the ExpressionAttributeValues array, and as far as I can determine this is constructed correctly.
The exception message is making me think of a type mismatch between the supplied value in the query and the type of the column being queried. Is that the correct interpretation? But that cannot be the case - as you can see below, the room
column is defined as S
for String. Hence this is a string comparison and should be fine.
Again - I am not using the DocumentClient. I've seen plenty of answers suggesting to simplify the query by using that client. I'm not using it.
The table is defined in the Serverless serverless.yml
as so:
MessagesDynamoDBTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: messageId
AttributeType: S
- AttributeName: room
AttributeType: S
- AttributeName: userId
AttributeType: S
KeySchema:
- AttributeName: messageId
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: roomIndex
KeySchema:
- AttributeName: room
KeyType: HASH
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
- IndexName: userIndex
KeySchema:
- AttributeName: userId
KeyType: HASH
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.tableName}
The table has a simple primary key and then two Global indexes each with simple primary keys.
The query code:
const params = {
TableName: MESSAGES_TABLE,
IndexName: "roomIndex",
KeyConditionExpression: "room = :room",
ExpressionAttributeValues: {
":room": { S: `${req.params.room}` }
},
};
console.log(`QUERY ROOM ${JSON.stringify(params)}`);
dynamoDb.query(params, (error, result) => {
if (error) {
console.log(error);
res.status(400).json({ error: 'Could not get messages' });
} else {
res.json(result.Items);
}
});