我们说我有一个DynamoDB表,例如
TableName: 'Items'
Key: {Hash: 'Id'}
每个项目都有一个名称,属于一个客户,所以我也有一个索引
{Hash: CustomerId, Range:Name}
我们说我有这些数据:
Id CustomerId Name
1 18 Milk
2 42 Orange juice
3 42 Apple juice
4 42 Coffee
5 54 Tomato juice
现在,我想查询特定客户的所有项目,并过滤部分名称的结果(本质上是搜索操作)。例如,给我所有属于客户42的物品,其中包含" juice"以它的名字(橙汁和苹果汁是预期的结果)。
如果我查询CustomerId = '42' AND contains(Name, 'juice')
,我会收到错误消息,指出KeyConditionExpression
不支持contains
。我可以理解这个限制,因为contains
表示必须扫描所有项目(在给定的哈希键内),但是,你可以查询所有 CustomerId = '42'
的项目也是该哈希内的完整扫描,因此我不确定我是否理解此限制。像begins_with
这样的东西得到了正常的支持(这很有意义,因为很容易从排序的集合中快速返回一个子集)。
无论如何,所以我诅咒了一下,然后说我只是使用FilterExpression而是与浪费的RCU:s一起生活,导致查询
KeyConditionExpression: CustomerId = '42'
FilterExpression: contains(Name, 'juice')
但现在我收到一条错误消息,说我不允许在我的FilterExpression中包含主键属性("请改用KeyConditionExpression!")。
这让我陷入了两难境地。我无法使用contains
中的KeyCondition
进行过滤,因此无法在我Name
的{{1}}内进行过滤。我是否必须仅在CustomerId 上创建一个单独的索引才能实现我的用例,或者还有其他方法可以解决这个问题吗?
答案 0 :(得分:1)
对于这样的事情,你应该考虑复合键和 GSI重载的概念,并重新设计你的表以适应你的访问模式。
根据https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/
使用复合属性。尝试将多个属性组合到一起 如果符合您的访问模式,则形成唯一密钥。例如, 考虑使用customerid + productid + countrycode作为的订单表 partition key和order_date作为排序键。
所以你可以做一些事情,比如设计你的表以保持索引为customerid#name
答案 1 :(得分:0)
DynamoDB仅允许在关键条件下使用begin_with,因此不支持contains,但是对于您而言,可以按如下分层顺序排列rangeKey:
CustomerId Name
18 Milk
42 juice.Orange
42 juice.Apple
42 Coffee
54 Tomato juice
因此查询的结构可以像
KeyConditionExpression: CustomerId = '42' AND Name BEGINS_WITH 'juice'
答案 2 :(得分:0)
对于DynamoDB,我认为最好的解决方案是以您以后打算读取的形状存储数据。
如果发现自己需要复杂的读取查询,则可能陷入了期望DynamoDB像RDBMS那样的陷阱,事实并非如此。在 write 上转换和整形数据,使读取保持简单。
答案 3 :(得分:0)
此查询的行为类似于在关系数据库中的查询
database.scan()
.filterExpression('begins_with(#name ,:name) or begins_with(#someno,:name)')
.expressionAttributeNames({ "#name": "name","#someno":"someno"})
.expressionAttributeValues({ ":name" : data})
.exec().promise();
答案 4 :(得分:0)
只需复制属性并对其应用过滤器