amazon-dynamodb - DynamoDB查询二级索引ValidationException:条件参数类型与架构类型不匹配
问题描述
我正在使用无服务器框架开发 AWS 服务。到目前为止,它有一个表和几个全局二级索引。我正在尝试查询全局二级索引。
询问:
{
"TableName": "messages-table-dev",
"IndexName": "roomIndex",
"KeyConditionExpression": "room = :room",
"ExpressionAttributeValues": {
":room": {
"S": "everyone"
}
}
}
它给出了一个例外——使用 Node.js DynamoDB 客户端,而不是 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
我从文档中了解到 KeyConditionExpression 必须对分区索引进行相等匹配。在这种情况下,该room
字段是roomIndex
全局二级索引的分区索引。根据文档,您可以使用 ExpressionAttributeValues 数组将值替换为表达式,并且据我所知,这是正确构造的。
异常消息让我想到查询中提供的值与被查询列的类型之间的类型不匹配。这是正确的解释吗?但事实并非如此 - 正如您在下面看到的,该room
列被定义S
为 String。因此,这是一个字符串比较,应该没问题。
再次 - 我没有使用 DocumentClient。我已经看到很多答案建议通过使用该客户端来简化查询。我不使用它。
该表在无服务器中定义serverless.yml
如下:
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}
该表有一个简单的主键,然后是两个全局索引,每个索引都有简单的主键。
查询代码:
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);
}
});
解决方案
我不得不承认有点尴尬。我在问题中多次表示我的代码没有使用 DocumentClient,而是使用了 DynamoDB 类。
使用 DocumentClient,此查询确实有效:
{
"TableName": "messages-table-dev",
"IndexName": "roomIndex",
"KeyConditionExpression": "room = :room",
"ExpressionAttributeValues": {
":room": "everyone"
}
}
那是因为 DocumentClient 不需要这些数据类型,而是推导出数据类型。
事实证明,我的代码实际上是在使用 DocumentClient,一旦我从查询中删除数据类型,HTTP 请求就会按预期工作。而且,当转到 DynamoDB 客户端并添加回数据类型时,这也有效。
如果我更仔细地查看应用程序代码,就永远不会发布这个问题。
推荐阅读
- python - 为什么我不能使用 ALAnimationSpeech API 让 Nao 做特定的手势,比如 ^start()
- c# - 设备无关绘图
- rust - 如何使任何类型的parms生锈
- azure - Kubernetes - 服务类型 LoadBalancer 每次在 AKS 中部署时使用特定的 IP 地址
- android - 无法保存或加载列表
- r - 为分层条形图创建并排条形图
- templates - Github 拉取请求模板使用 config.yml 检测 YAML 前端内容并应用于字段
- python - 如何在运行时更改 Celery 的任务名称
- kotlin - Kotlin arrow-kt,将任一集合映射到任一集合的函数式方法
- centos - fail2ban - 如何在暂时禁止 3 次后永久禁止 IP