【问题标题】:How to prevent creating a new item in UpdateItem if the item does not exist如果项目不存在,如何防止在 UpdateItem 中创建新项目
【发布时间】:2017-06-11 22:37:10
【问题描述】:

我正在运行一个用 Node.js 编写的 AWS Lambda 服务,它与 DynamoDB 数据库交互。我的一种方法在 DynamoDB 上执行更新 (AWS.DynamoDB.DocumentClient().update) 以更新特定项目。但是,我的问题是,当我尝试更新一个项目并且该项目不存在时,更新方法会将这个新项目添加到我的表中。这种行为也是documentation 中描述的默认行为。

如果新项目尚不存在,我不希望我的方法创建它。我希望只有在记录存在时才进行更新。如果它不存在,它必须什么都不做。我如何实现这一目标?我希望我应该能够使用 ConditionalExpression 来实现这一点,但我在这方面所做的尝试并没有成功。

下面给出了我发送到更新函数的当前参数示例。在此示例中,我想更新具有 userId 123 的用户,并且我想将此用户的 isActive 字段设置为“false”(但我只想在用户 123 实际存在时这样做!)

const params = {
    TableName: 'users',
    Key: {
        userId: '123',
    },
    ExpressionAttributeValues: {
        ':isActive': 'false'
    },
    UpdateExpression: 'SET isActive = :isActive',
    ReturnValues: 'ALL_NEW',
};

【问题讨论】:

  • 如果有人想知道相反的情况:“如果密钥不存在,我如何使用 UpdateItem 创建新项目?”,那么只需使用 OP 发布的内容

标签: amazon-dynamodb


【解决方案1】:

您可以为此使用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 来检查该项目是否存在。 (来源:1、2)

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

【讨论】:

  • 这是我实际尝试过的选项之一。当我这样做时,我得到一个异常,ValidationException: Value provided in ExpressionAttributeValues used in expressions: keys: {:userIdVal}
  • 看起来您没有在表达式中提供 userIdVal。您是否在 ConditionExpression 中包含这部分“userId = :userIdVal”?
  • 确实有,并检查了拼写和语法。
  • 你能提供整个参数吗?我会看的。
  • 编辑后编写的代码确实有效。看起来最大的问题是我们的表达式属性值应该与我们在表中的属性具有明显不同的名称。因此,如果表属性称为 isActive,则表达式属性值不应为 :isActive(但如果将其更改为 :isActiveVal 则有效)。
【解决方案2】:

ConditionExpression 是要走的路,但你也可以使用attribute_exists 函数:

ConditionExpression: 'attribute_exists(userId)'

它只会使用正确的密钥更新行并在请求的密钥不存在时抛出ConditionalCheckFailedException。

目标更明显,可以跳过额外的 userId 绑定。

参考:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html

【讨论】:

  • 对我不起作用,它仍然在 updateItem 调用中添加了一个新项目
  • @SaileshKotha 只有当我使用未被update_item 和Keyparameter 修改的密钥时,它才对我有用。
【解决方案3】:

我在使用attribute_exists 时遇到了一个类似的问题,唯一的区别是,我需要从表中查询并只获取具有我需要的属性的记录。使用ConditionExpression 对我不起作用。想在这里分享一下,以防有人需要。

这里,如果subscriberKey等于给定参数和记录中的attribute_exists(mobileNumber),则返回true,否则返回false。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    • 2017-07-13
    • 1970-01-01
    • 2011-10-09
    • 2019-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多