Node.js操作DynamoDB报错:提供的键元素与schema不匹配
解决DynamoDB的"The provided key element does not match the schema"错误
我帮你定位到了两个核心问题,都是触发这个错误的根源,咱们一步步来修复:
1. 你的DynamoDB表配置违反了DynamoDB的规则
DynamoDB对表的主键结构有严格限制:每个表只能有一个HASH(分区)键,最多只能有一个RANGE(排序)键。你在serverless.yml的KeySchema里配置了1个HASH键+3个RANGE键,这完全不合法!错误的表结构会导致后续所有操作的键参数都无法匹配预期,直接触发报错。
修正表配置方案
你需要先明确业务主键策略,再调整表结构:
- 如果
id是每条记录的唯一标识,只需要把id设为HASH键,其他属性作为普通字段; - 如果需要按
in_organization_id分组查询,可以把id设为HASH键,in_organization_id设为唯一的RANGE键; - 如果需要通过
sp_customer_id或qb_customer_id查询记录,给这些字段创建**全局二级索引(GSI)**即可,不要把它们设为主键的一部分。
修正后的serverless.yml示例:
Resources: TodosDynamoDbTable: Type: 'AWS::DynamoDB::Table' DeletionPolicy: Retain Properties: AttributeDefinitions: - AttributeName: id AttributeType: S - AttributeName: in_organization_id AttributeType: S - AttributeName: sp_customer_id AttributeType: S - AttributeName: qb_customer_id AttributeType: S KeySchema: - AttributeName: id KeyType: HASH # 唯一的分区键 - AttributeName: in_organization_id KeyType: RANGE # 最多只能有一个排序键 # 为其他查询字段添加全局二级索引 GlobalSecondaryIndexes: - IndexName: spCustomerIndex KeySchema: - AttributeName: sp_customer_id KeyType: HASH Projection: ProjectionType: ALL ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 - IndexName: qbCustomerIndex KeySchema: - AttributeName: qb_customer_id KeyType: HASH Projection: ProjectionType: ALL ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1 TableName: 'insightly'
2. Get/Update操作未传入完整的主键
DynamoDB的get和update操作必须传入完整的主键(HASH键+RANGE键,如果表配置了RANGE键的话)。你现在只传了in_organization_id,完全没包含HASH键id,这必然会触发键不匹配的错误。
修正Update方法
/* Update Record in DB */ this.UpdateDB = (event) => { return new Promise(async (resolve, reject) => { try { const data = event; const params = { TableName: process.env.TABLE_NAME, Key: { id: data.id, // 必须传入HASH键id in_organization_id: data.in_organization_id // 必须传入RANGE键 }, UpdateExpression: "set qb_customer_id = :qb_customer_id", ExpressionAttributeValues:{ ":qb_customer_id": data.qb_customer_id }, ReturnValues:"UPDATED_NEW" }; const response = await dynamoDb.update(params).promise(); resolve(response); } catch (err) { reject(err.message); } }); };
修正Get方法
注意:get方法只能查询单条记录,必须传入完整主键。如果你的需求是查询某个in_organization_id下的所有记录,应该用query方法配合主键或GSI,而不是get。
/* Get Single Record by Full Primary Key */ this.checkOrgID = (OrgID, recordId) => { // 需要传入对应的记录id return new Promise(async (resolve, reject) => { try { const params = { TableName: process.env.TABLE_NAME, Key: { id: recordId, // 必须传入HASH键id in_organization_id: OrgID } }; const response = await dynamoDb.get(params).promise(); resolve(response); } catch (err) { reject(err.message); } }); };
附加:查询某组织下所有记录的示例(用query)
如果你的需求是查询某个in_organization_id对应的所有记录,可以用这个方法:
/* Get All Records for an Organization */ this.getRecordsByOrgID = (OrgID) => { return new Promise(async (resolve, reject) => { try { const params = { TableName: process.env.TABLE_NAME, // 如果in_organization_id是RANGE键,需要和HASH键组合查询 KeyConditionExpression: "id = :dummyId AND in_organization_id = :orgId", ExpressionAttributeValues: { ":dummyId": "*", // 这里需要根据实际业务调整,或直接用GSI查询 ":orgId": OrgID }, // 若给in_organization_id建了GSI,可直接指定索引查询 // IndexName: "orgIdIndex" }; const response = await dynamoDb.query(params).promise(); resolve(response.Items); } catch (err) { reject(err.message); } }); };
最后提醒:修改表结构后,需要重新部署Serverless服务,让新的表结构生效。
内容的提问来源于stack exchange,提问作者Awadhesh Kumar
相关产品推荐
相关产品推荐

