具有多种条件的 Dynamo putItem 在 localstack 中不起作用

Dynamo putItem with multiple conditions not working in localstack

我第一次直接使用 Dynamo,在本地的玩具项目中。我正在尝试创建一个由条件表达式保护的记录 - 如果用户名(范围键)或 uniqueId(哈希键)已经存在,则失败:"attribute_not_exists(UserId) and attribute_not_exists(Username)"。但是,当我放置具有相同用户名的记录时,我没有遇到冲突 - table 的扫描证实了这一点。我正在使用 localstack(本地 AWS 模拟),如果这有所不同的话。

问题:

创建记录的逻辑如下:

userID := GenerateUniqueID()
record := UserCredentialsRecord{
    UserID:           userID,
    Username:         username,
    Password:         base64.StdEncoding.EncodeToString(hashedPassword),
    Salt:             base64.StdEncoding.EncodeToString(salt),
    Email:            email,
    AccountCreatedTS: time.Now().Unix(),
}
...

input := &dynamodb.PutItemInput{
    Item:                av,
    TableName:           aws.String(userCredentialsTableName),
    ConditionExpression: aws.String("attribute_not_exists(UserId) and attribute_not_exists(Username)"),
}
...

_, err = session.PutItem(input)
if err != nil {
    fmt.Println("Got error calling PutItem:", err.Error())
}

这是本地堆栈中的 Dynamo table:

localstack         | ++ aws --endpoint-url=http://localstack:4566 dynamodb create-table --table-name UserCredentials --attribute-definitions AttributeName=UserID,AttributeType=S AttributeName=Username,AttributeType=S --key-schema AttributeName=UserID,KeyType=HASH AttributeName=Username,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
localstack         | {
localstack         |     "TableDescription": {
localstack         |         "AttributeDefinitions": [
localstack         |             {
localstack         |                 "AttributeName": "UserID",
localstack         |                 "AttributeType": "S"
localstack         |             },
localstack         |             {
localstack         |                 "AttributeName": "Username",
localstack         |                 "AttributeType": "S"
localstack         |             }
localstack         |         ],
localstack         |         "TableName": "UserCredentials",
localstack         |         "KeySchema": [
localstack         |             {
localstack         |                 "AttributeName": "UserID",
localstack         |                 "KeyType": "HASH"
localstack         |             },
localstack         |             {
localstack         |                 "AttributeName": "Username",
localstack         |                 "KeyType": "RANGE"
localstack         |             }
localstack         |         ],
localstack         |         "TableStatus": "ACTIVE",
localstack         |         "CreationDateTime": 1610668286.312,
localstack         |         "ProvisionedThroughput": {
localstack         |             "LastIncreaseDateTime": 0.0,
localstack         |             "LastDecreaseDateTime": 0.0,
localstack         |             "NumberOfDecreasesToday": 0,
localstack         |             "ReadCapacityUnits": 1,
localstack         |             "WriteCapacityUnits": 1
localstack         |         },
localstack         |         "TableSizeBytes": 0,
localstack         |         "ItemCount": 0,
localstack         |         "TableArn": "arn:aws:dynamodb:us-east-1:000000000000:table/UserCredentials"
localstack         |     }
localstack         | }

在 DynamoDB 中,hash key + range key 构成主键。或者,只有 hash key,如果我们没有为我们的 table 定义 range key

所以,你想要的不能在范围键上完成,因为它不是唯一的。

这里要注意的是 - attribute_not_exists 不会为您扫描 table,而是检查您正在使用的 record/item(来自散列键和 ddb 查询中的范围键)。

您对 attribute_not_exists 条件表达式的作用有误解。

这并不意味着该属性在 任何 项上不存在于 table,而是该属性在您的项上不存在正在与.

因此,操作按设计进行。

如果您想确保没有两个项目被添加到 table 具有相同的用户名或用户 ID,您将不得不使用这两个属性作为 [=21] 的主键=],或想出一种检查重复项的替代方法。