Reputation: 988
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);
}
});
Upvotes: 2
Views: 5171
Reputation: 988
I have to admit to a bit of embarrassment. I said several times in the question that my code was not using the DocumentClient but was using the DynamoDB class.
With DocumentClient, this query does indeed work:
{
"TableName": "messages-table-dev",
"IndexName": "roomIndex",
"KeyConditionExpression": "room = :room",
"ExpressionAttributeValues": {
":room": "everyone"
}
}
That's because DocumentClient does not require those data types, and instead it deduces the data types.
Turns out that my code actually was using DocumentClient, and that as soon as I removed the data type from the query the HTTP request worked as expected. And, when going to the DynamoDB client and adding back the data types, that also worked.
If I had looked more carefully at the application code, this question would never have been posted.
Upvotes: 4
Reputation: 93
{
"TableName": "messages-table-dev",
"IndexName": "roomIndex",
"KeyConditionExpression": "room = :room",
"ExpressionAttributeValues": {
":room": "everyone"
}
}
There is no need of putting data type while querying to dynamoDb
Upvotes: 4