DynamoDB主键不存在时插入数据、存在时不更新返回原数据的实现问题
解决方案
你需要的「主键不存在时创建条目、主键已存在时不更新直接返回原有数据」的逻辑,有两种成熟实现方式。你之前putItem报错的原因是:if_not_exists 函数仅允许在 UpdateExpression 中使用,不能用于 ConditionExpression,条件判断属性不存在直接用 attribute_not_exists() 函数即可。
方案1:修正putItem实现(适合全条目写入场景)
修改ConditionExpression为判断主键不存在,同时新增异常分支处理主键已存在的场景,捕获到ConditionalCheckFailedException时主动查询原有数据返回:
const str = randomize('Aa0', 6); const params = { TableName: "alexa-connections-table", Item: { "alexaDeviceId": { S: process.env.TEST_ALEXA_DEVICE_ID }, "connectionString": { S: str } }, // 仅当主键不存在时才执行put操作 ConditionExpression: 'attribute_not_exists(alexaDeviceId)' }; try { await dynamodb.putItem(params).promise(); // 写入成功直接返回新写入的数据 const result = { Attributes: params.Item }; console.log('Results: ' + JSON.stringify(result)); return res.status(200).send(JSON.stringify(result)); } catch (err) { // 捕获条件校验失败的异常,说明主键已存在 if (err.code === 'ConditionalCheckFailedException') { // 查询原有数据返回 const getParams = { TableName: "alexa-connections-table", Key: { "alexaDeviceId": { S: process.env.TEST_ALEXA_DEVICE_ID } } }; const existResult = await dynamodb.getItem(getParams).promise(); return res.status(200).send(JSON.stringify({Attributes: existResult.Item})); } console.log(err); return res.status(500).send({ reason: err }); }
方案2:修正updateItem实现(更简洁,无需额外查询)
利用updateItem自带的「主键不存在自动创建」特性,结合if_not_exists函数实现仅属性不存在时赋值,无需额外异常处理和查询:
const str = randomize('Aa0', 6); const params = { TableName: "alexa-connections-table", Key: { "alexaDeviceId": { S: process.env.TEST_ALEXA_DEVICE_ID } }, ExpressionAttributeNames: { "#CS": "connectionString" }, ExpressionAttributeValues: { ":connection": { S: str } }, ReturnValues: "ALL_NEW", // 仅当connectionString不存在时才赋值 UpdateExpression: "SET #CS = if_not_exists(#CS, :connection)" }; try { const result = await dynamodb.updateItem(params).promise(); console.log('Results: ' + JSON.stringify(result)); return res.status(200).send(JSON.stringify(result)); } catch (err) { console.log(err); return res.status(500).send({ reason: err }); }
如果需要严格限制「只要主键存在就完全不执行任何写入操作」,可以在上述updateItem参数中额外添加ConditionExpression: 'attribute_not_exists(alexaDeviceId)',之后和方案1一样捕获ConditionalCheckFailedException异常查询旧数据返回即可。
内容的提问来源于stack exchange,提问作者WHOATEMYNOODLES
相关产品推荐
相关产品推荐

