如何在UpdateItem中防止创建新项目,如果该项目不存在

73
我正在运行一个使用Node.js编写的AWS Lambda服务,它与DynamoDB数据库交互。我的其中一个方法执行了一个更新(AWS.DynamoDB.DocumentClient().update),用于更新特定项的DynamoDB。然而,我的问题是,当我尝试更新一个不存在的项目时,更新方法会将此新项目添加到我的表中。这种行为在文档中也是默认描述的。
如果记录不存在,我不希望我的方法创建新项目。我希望这只是一个更新,仅在记录存在时才进行更新。如果不存在,则不执行任何操作。我该如何实现这一点?我认为我应该能够使用ConditionalExpression来实现这一点,但我尝试过的方法都没有成功。
下面是我当前发送给更新函数的参数示例。在此示例中,我要更新具有userId 123的用户,并将isActive字段设置为“false”(但我只想在用户123实际存在时才这样做!)
const params = {
    TableName: 'users',
    Key: {
        userId: '123',
    },
    ExpressionAttributeValues: {
        ':isActive': 'false'
    },
    UpdateExpression: 'SET isActive = :isActive',
    ReturnValues: 'ALL_NEW',
};

5
如果有人想知道相反的情况:"如果键不存在,如何使用UpdateItem创建新项目?",那么只需使用OP所发布的内容。 - denvercoder9
3个回答

78
你可以使用 ConditionExpression 来实现此操作。如果键(即 userId)存在且更新属性(即 isActive)不等于你要更新的新值,则会发生更新。
ConditionExpression: "userId = :userIdVal and isActive <> :isActiveVal",
ExpressionAttributeValues: {
    ':isActive': 'false',
    ':userIdVal': '123'
},

编辑:

这应该可以工作。应该是 ConditionExpression(而不是ConditionalExpression)

var params = {
    TableName: 'users',
    Key: {
        'userId': '123'
    },
    UpdateExpression: 'SET isActive = :isActiveVal',
    ConditionExpression: 'userId = :userIdVal and isActive <> :isActiveVal',
    ExpressionAttributeValues: {
        ':userIdVal': '123',
        ':isActiveVal': 'false'
    },
    ReturnValues: "ALL_NEW"
};

更新,2020年:

您可以在 ConditionExpression 中使用 attribute_exists 来检查该项是否存在。(来源:12)

const params = {
    TableName: 'users',
    Key: {
        'userId': '123'
    },
    UpdateExpression: 'SET isActive = :isActiveVal',
    ConditionExpression: 'attribute_exists(userId)',
    ExpressionAttributeValues: {
        ':isActiveVal': 'false'
    },
    ReturnValues: "ALL_NEW"
};

这是我实际尝试过的选项之一。当我这样做时,我会得到一个异常,即ValidationException:在表达式中未使用ExpressionAttributeValues中提供的值:keys:{:userIdVal}。 - Stanley
看起来您在表达式中没有提供 userIdVal。您是否在 ConditionExpression 中包括了这部分 "userId = :userIdVal"? - notionquest
确实,我已经检查了拼写和语法。 - Stanley
请提供完整的参数吗?我会查看它。 - notionquest
如果需要,我们可以在聊天中讨论... http://chat.stackoverflow.com/rooms/134084/room-for-notionquest-and-stanley - notionquest
1
经过您的编辑,代码确实可以工作。看起来最大的问题是我们的表达式属性值应该与表中的属性具有明显不同的名称。因此,如果表属性被称为isActive,则不应该将ExpressionAttributeValue命名为:isActive(但如果您将其更改为 :isActiveVal,它就可以工作)。 - Stanley

44

对我没用,它仍然在updateItem调用时添加了一个新项。 - Sailesh Kotha
1
@SaileshKotha 只有在我使用 update_item 不修改的 Key 和 Key 参数时,它才对我有效。 - Vikto

2
我在使用attribute_exists时遇到了类似的问题,区别仅在于我需要从表中进行查询,并且只获取具有所需属性的记录。使用ConditionExpression对我无效。在这里分享一下,以防有人需要。
如果subscriberKey等于给定参数,并且记录中存在mobileNumber属性,则返回true,否则返回false

var params = {
    TableName : table_name,
    IndexName: "subsciberKey-index",
    KeyConditionExpression: "subscriberKey = :subscriberKey",
    FilterExpression: "attribute_exists(mobileNumber)",
    ExpressionAttributeValues: {
        ":subscriberKey": subscriberNo
    }
};


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接