使用“包含”查询 DynamoDB 项目

JHH*_*JHH 11 amazon-dynamodb

假设我有一个 DynamoDB 表,例如

TableName: 'Items'
Key: {Hash: 'Id'}
Run Code Online (Sandbox Code Playgroud)

每个项目都有一个名称并属于一个客户,所以我也有一个索引

{Hash: CustomerId, Range:Name}
Run Code Online (Sandbox Code Playgroud)

假设我有这个数据:

Id    CustomerId    Name
1     18            Milk
2     42            Orange juice
3     42            Apple juice
4     42            Coffee
5     54            Tomato juice
Run Code Online (Sandbox Code Playgroud)

现在,我想查询特定客户的所有项目并过滤部分名称的结果(本质上是搜索操作)。例如,给我属于客户 42 名称中包含“果汁”的所有项目(橙汁和苹果汁是预期结果)。

如果我查询CustomerId = '42' AND contains(Name, 'juice')我会得到一个错误,KeyConditionExpression说不支持contains. 我可以理解这个限制,因为这contains意味着必须扫描所有项目(在给定的散列键内),但是,好吧,你可以查询在该散列中也是完整扫描的所有项目CustomerId = '42',所以我不确定我理解这个限制。像begins_with预期的那样支持之类的东西(这是有道理的,因为很容易从排序集中快速返回一个子集)。

无论如何,所以我有点诅咒并说我将只使用 FilterExpression 并与浪费的 RCU:s 一起生活,从而导致查询

KeyConditionExpression: CustomerId = '42'
FilterExpression: contains(Name, 'juice')
Run Code Online (Sandbox Code Playgroud)

但是现在我收到一条错误消息,说我不允许在我的 FilterExpression 中包含主键属性(“改用 KeyConditionExpression!”)。

这让我有些进退两难。我无法contains在我的中过滤,KeyCondition也无法Name在我的FilterExpression. 我是否应该只在 CustomerId 上创建一个单独的索引才能实现我的用例,还是有其他方法可以解决这个问题......?

小智 11

DynamoDB仅允许begin_with()关键条件。因此contains()不支持,但对于您的情况,可以按分层顺序排列 rangeKey,如下所示:

CustomerId    Name
18            Milk
42            juice.Orange 
42            juice.Apple
42            Coffee
54            Tomato juice
Run Code Online (Sandbox Code Playgroud)

所以查询的结构可以是这样的

KeyConditionExpression: CustomerId = '42' AND Name BEGINS_WITH 'juice'
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 唯一的使用方法contains()似乎是在过滤表达式中,并且过滤表达式只能对非键进行操作。


Llo*_*oyd 11

对于 DynamoDB,我认为最好的解决方案是以您以后打算阅读的形状存储数据。

如果您发现自己需要复杂的读取查询,您可能会陷入期望 DynamoDB 表现得像 RDBMS 的陷阱,而事实并非如此。在写入时转换和整形您的数据,保持读取简单。


Sha*_*aho 3

对于这样的东西,您应该考虑复合键GSI 重载的概念,并重新设计您的表以适应您的访问模式。

根据https://aws.amazon.com/blogs/database/choosing-the-right-dynamodb-partition-key/

使用复合属性。如果符合您的访问模式,请尝试组合多个属性来形成唯一的键。例如,考虑一个订单表,其中 customerid+productid+countrycode 作为分区键,order_date 作为排序键。

所以你可以做一些事情,比如设计你的表来保存索引customerid#name