Reputation: 5082
I'm using Dynamo for the first time directly, in toy project locally. I'm trying to create a record guarded by a condition expression- if the username (range key) or uniqueId (hash key) already exist, fail: "attribute_not_exists(UserId) and attribute_not_exists(Username)"
. However, when I put records with the same usernames, I don't get a conflict- and a scan of the table confirms this. I am using localstack (local AWS analog), if that makes a difference.
Questions:
Here's the logic to create the record:
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())
}
Here's the Dynamo table in localstack:
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 | }
Upvotes: 0
Views: 762
Reputation: 387
In DynamoDB, hash key
+ range key
forms the primary key. Or, only hash key
, if we don't have range key
defined for our table.
So, what you want can't be done on range-key as that is not a unique.
The point to not here is that - attribute_not_exists
doesn't scans the table for you, rather checks the record/item you are working with (which comes from hash-key and range-key in your ddb query).
Upvotes: 1
Reputation: 55760
You have a misconception about what the attribute_not_exists
conditional expression does.
It doesn't mean that the attribute does not exist on any item in the table, but rather that the attribute doesn't exist on the item you are working with.
As such, the operation is working as designed.
If you want to make sure that no two items are added to the table with the same username, or user id, you will have to use those two attributes as the primary key for the table, or come up with an alternative method to check for duplicates.
Upvotes: 4