问题:
主键为复合哈希范围键的 DynamoDB 表是唯一的。这也适用于二级指数吗?
示例:
我有一个评论 DynamoDB 表,其中包含 post_id 主键和 comment_id 范围键。 此外,还有一个带有 date-user_id 范围键的本地二级索引。
每个条目都是用户在帖子上留下的评论。二级索引的目的是计算特定日期有多少唯一用户对帖子发表评论。
条目1: 帖子 ID:1 评论 ID:1 日期-user_id:2014_06_24-1
条目2: 帖子 ID:1 评论 ID:2 日期-user_id:2014_06_24-1
条目3: 帖子 ID:1 评论 ID:3 日期-user_id:2014_06_24-2
当我执行指定二级索引的查询,并传入 post_id 等于 1 且 date-user_id 等于 2014_06_24-1 的条件时,我得到的计数为 2,并且我期望计数为 1。
为什么二级索引有两个主键/范围键相同的条目。
二级索引不保证唯一性。 来自文档:
在 DynamoDB 表中,每个键值必须是唯一的。但是,全局二级索引中的键值不需要是唯一的。
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.scenario
不,他们没有。索引是异步更新的,这意味着它们最终将保持一致,这也意味着 dynamodb 在您进行更新调用时将无法强制执行唯一性(它不会检查二级索引的唯一性,因为这是一个异步操作;如果这样做,它将无法返回失败,因为实时调用已经完成)。
顺便说一句,这也是为什么您只能对 GSI 索引执行扫描或查询,而不能对 GetItem 执行扫描或查询的原因(即 GetItem 预计返回一项,但在没有唯一性约束)。
其实可以通过事务和多表的组合来保证一个GSI的唯一性。
例如假设您的主表有这些索引:
record_id(分区键) 名称(GSI)
如果要确保“name”在此表中唯一,请创建具有以下索引的辅助表:
名称(分区键)
然后,在主表中创建文档时,将其作为事务的一部分执行,同时在第二个表中创建文档,并使用特殊条件确保该名称尚不存在,例如该交易将有以下更新:
PutItem(Table=mainTable, ConditionExpression='attribute_not_exists(#RECORD_ID)',...)
PutItem(Table=namesTable,ConditionExpression='attribute_not_exists(#NAME)',...)
从主表中删除一个项目还可以确保两个文档都从事务中的两个表中删除,这基本上保证了引用完整性。
本地二级索引 (LSI) 中的每个项目与表中的相应项目具有 1:1 的关系。 在上面的示例中,虽然 LSI 中的条目 1 和条目 2 具有相同的范围键值,但它们指向的表中的项目不同。因此索引键(散列或散列+范围)不是唯一的。
全球二级指数(GSI)在这方面与LSI类似。每个 GSI 项目都包含(相应项目的)表哈希和范围键。更多详细信息请访问 http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Projections
DynamoDB 不保证二级索引的唯一性,但它保证主索引的唯一性,我们可以用它来实现我们自己的唯一索引。
简而言之,您需要为每个评论创建多条记录,第一个用于保存评论本身,第二个用于处理
date-user_id
唯一索引。另外,每次插入新记录或更新记录时都需要添加条件表达式。
这是我们的记录的样子
{
pk: '<post_id>_<comment_id>',
record_type: 'record',
date-user_id: '2022-05-13_<user-id>',
comment: 'some comment'
}
{
pk: 'unique-index#2022-05-13_<user-id>',
record_type: 'unique-index'
}
每次向数据库插入新评论时,您都需要使用 DynamoDB 写入事务插入两条记录,并检查这两条记录是否没有任何其他记录具有相同的
pk
。
这是关于如何操作的我的文章。您可以在那里找到详细的描述和广泛的代码示例