这是我第一次使用DynamoDB,并为系统中的用户帐户创建了一个表。
表格定义如下:
{
"Table": {
"AttributeDefinitions": [
{
"AttributeName": "AccountId",
"AttributeType": "B"
},
{
"AttributeName": "Email",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "AccountId",
"KeyType": "HASH"
}
],
"GlobalSecondaryIndexes": [
{
"IndexName": "EmailAddress",
"KeySchema": [
{
"AttributeName": "Email",
"KeyType": "HASH"
}
],
"Projection": {
"ProjectionType": "ALL"
},
"IndexStatus": "ACTIVE"
}
]
}
}
为了简洁起见,省略了一些字段
我使用的是Rusoto DynamoDB客户端,这就是PutItem
调用的样子:
dynamodb_client.put_item(PutItemInput{
item: account_doc.as_hashmap(),
table_name: accounts_datastore_name,
condition_expression: Some("attribute_not_exists(Email) and attribute_not_exists(AccountId)".to_string()),
..PutItemInput::default()
});
据我所知,这应该具有以下行为:如果有文档包含我在新文档中提供的值为Email
的AccountId
,则事务失败。
我已经能够多次提交同一份文档,而服务没有任何错误。文件都在表格里。
你知道为什么这个条件表达式允许文档通过吗?
您误解了条件的作用。它不查看表中的其他记录,只查看您正在put
处理的记录。想象一下以下两条记录:
{
"AccountId": "<some_unique_id_1>",
"Email": "user@example.com"
}
和
{
"AccountId": "<some_unique_id_2>",
"Email": "user@example.com"
}
其中的每一个都将被保存,因为AccountId
值不同,这意味着它在表中是不同的记录。
你的条件会阻止你第二次用相同的AccountId
写唱片。因为AccountId
是记录的关键,并且您要确保正在写入的记录没有设置AccountId
,所以只有在第一次写入时才能写入该记录。在这种情况下,条件的Email
部分实际上没有做任何事情。
对于你想要的东西,你可以考虑两种选择。
- 将密钥切换为电子邮件地址。这将确保电子邮件地址是唯一的
- 使用事务来写入您的记录。这并不像听起来那么简单。Alex DeBrie有一篇关于使用交易的非常好的文章