DynamoDB documentClient.transactWrite触发ValidationException,类型却正确
问题
重写代码使用DynamoDB事务API更新产品信息对象时,遇到以下错误:ValidationException: ExpressionAttributeValues contains invalid value: The parameter cannot be converted to a numeric value: NaN for key :products
:products确实为NaN,它的TypeScript类型是{productId:number, price:number}[],和数据库中现有类型一致。从DDB获取对象后,仅修改元素顺序、删除部分元素、调整部分价格,再将同类型对象写回。
使用TypeScript SDK,相关代码如下:
const PRODUCTS_STATE_OBJECT_TYPE = "Products" as const; type Product = { id: number; price: number }; type ProductsState = { objectType: typeof PRODUCTS_STATE_OBJECT_TYPE; objectIndex: number; lastUpdate: string; products: Array<Product>; } const client = new DocumentClient({ convertEmptyValues: true }); const productsQueryResult = await client .query({ TableName: TABLE_NAME!, KeyConditionExpression: `objectType = :objectType`, ExpressionAttributeValues: { ":objectType": PRODUCTS_STATE_OBJECT_TYPE, }, }) .promise(); const productsArray:Array<Array<Product>> = ((productsQueryResult.Items ?? []) as Array<ProductsState>).map(({products})=>products) // 一堆修改productsArray为newProductsArray的代码,类型保持一致 const newProductsStates: Array<ProductsState> = newProductsArrays.map((products, objectIndex) => ({ objectType: PRODUCTS_STATE_OBJECT_TYPE, objectIndex, lastUpdate: getCurrentDateString(), products, })); const newProductsStatesRequestObjects: DocumentClient.TransactWriteItemList = newProductsStates.map( ({ objectIndex, objectType, lastUpdate, products }) => ({ Update: { TableName: TABLE_NAME!, Key: { objectType, objectIndex }, UpdateExpression: "set " + ["lastUpdate = :lastUpdate", "products = :products"].join(","), ExpressionAttributeValues: { ":lastUpdate": lastUpdate, ":products": products, }, }, }) ); await client .transactWrite({ TransactItems: [ ...newProductsStatesRequestObjects, ], }) .promise();
products不是数值类型,也没定义校验规则,且和待更新的数据库对象类型一致。完整错误信息:
ValidationException: ExpressionAttributeValues contains invalid value: The parameter cannot be converted to a numeric value: NaN for key :products at Request.extractError (/var/task/index.js:316:32) at Request.callListeners (/var/task/index.js:3336:24) at Request.emit (/var/task/index.js:3311:14) at Request.emit (/var/task/index.js:8496:18) at Request.transition (/var/task/index.js:8099:15) at AcceptorStateMachine.runTo (/var/task/index.js:6537:16) at /var/task/index.js:6552:15 at Request.<anonymous> (/var/task/index.js:8115:13) at Request.<anonymous> (/var/task/index.js:8499:16) at Request.callListeners (/var/task/index.js:3346:22) { code: 'ValidationException', '[__type]': 'See error.__type for details.', time: 2024-03-07T02:36:33.519Z, requestId: '9IACI23LBETVAHCVSKDT28EBV7VV4KQNSO5AEMVJF66Q9ASUAAJG', statusCode: 400, retryable: false, retryDelay: 1.4080887836606215 }
已通过console.log确认对象类型正确。
解决方案
- 检查产品价格是否生成NaN:TypeScript类型定义是
number不代表实际值不会出错,比如价格调整时的除以0、非数字字符串转数字操作都会生成NaN。在生成newProductsArrays后,遍历过滤或替换NaN值:// 示例:将NaN替换为0,也可根据业务逻辑抛出错误或使用默认值 const sanitizedProducts = products.map(p => ({ ...p, price: isNaN(p.price) ? 0 : p.price })); - 校验数组本身有效性:排查是否有错误赋值导致数组变成NaN的情况,在生成
newProductsStates前添加校验:newProductsArrays.forEach((arr, index) => { if (!Array.isArray(arr)) { throw new Error(`索引${index}的products不是有效数组: ${arr}`); } }); - 调整DocumentClient配置:当前开启了
convertEmptyValues: true,可能在边缘场景下导致数组被异常转换,尝试移除该配置:const client = new DocumentClient(); - 临时替换为Put操作排查:如果Update操作问题仍存在,用Put操作替换Update,确认是否是Update表达式的问题:
// 替换原Update逻辑为Put newProductsStates.map((item) => ({ Put: { TableName: TABLE_NAME!, Item: item } }))
内容的提问来源于stack exchange,提问作者MWHmann
相关产品推荐
相关产品推荐

