使用Between运算符查询DynamoDB返回全部结果的问题求助
问题描述
表结构
DynamoDB表结构如下:
key reference value 1234 3214#0012345 xxxx 1234 3314#0003455 xxxx 1234 3214#0004231 xxxx
其中reference字段由${accountId}#${idOfItem}拼接而成。
需求
查询指定key下,匹配指定accountId的value数据。
现有Java代码
public Promise<List<Value>> getFiltersByUser(Key key, AccountId accountId) { final QuerySpec query = new QuerySpec(); Map<String, Object> valueMap = new HashMap<>(); Map<String, String> keyMap = new HashMap<>(); keyMap.put("#key", PARTITION_KEY_NAME); keyMap.put("#reference", RANGE_KEY_NAME); valueMap.put(":key", key); valueMap.put(":startReference", createFilterRef("0000000", accountId)); valueMap.put(":endReference", createFilterRef("9999999", accountId)); //createFilterRef simply creates the reference by concatenating the two values with hashtag query.withKeyConditionExpression("#key = :key AND #filterRef BETWEEN :startFilterRef AND :endReference") .withNameMap(keyMap) .withValueMap(valueMap); return Blocking.get(() -> { final ItemCollection<QueryOutcome> out = table.query(query); return newArrayList(out) .stream() .map(this::createValueFromItem)//we can disregard this as it converts the results received to a different structure .collect(Collectors.toList()); }); }
遇到的问题
查询条件中的BETWEEN运算符未生效,返回了指定key下的所有结果。
解决方案
问题根源
代码存在两处占位符名称不匹配的问题,导致BETWEEN条件未正确关联到reference字段:
NameMap中定义的范围键占位符是#reference,但KeyConditionExpression里用的是#filterRef,DynamoDB无法识别未映射的占位符,直接忽略该条件片段。ValueMap中定义的起始值占位符是:startReference,但表达式里用的是:startFilterRef,导致值无法正确绑定。
修正后的代码
修改KeyConditionExpression中的占位符,使其与NameMap和ValueMap的定义完全匹配:
public Promise<List<Value>> getFiltersByUser(Key key, AccountId accountId) { final QuerySpec query = new QuerySpec(); Map<String, Object> valueMap = new HashMap<>(); Map<String, String> keyMap = new HashMap<>(); keyMap.put("#key", PARTITION_KEY_NAME); keyMap.put("#reference", RANGE_KEY_NAME); valueMap.put(":key", key); valueMap.put(":startReference", createFilterRef("0000000", accountId)); valueMap.put(":endReference", createFilterRef("9999999", accountId)); // 修正占位符名称,与NameMap、ValueMap对应 query.withKeyConditionExpression("#key = :key AND #reference BETWEEN :startReference AND :endReference") .withNameMap(keyMap) .withValueMap(valueMap); return Blocking.get(() -> { final ItemCollection<QueryOutcome> out = table.query(query); return newArrayList(out) .stream() .map(this::createValueFromItem) .collect(Collectors.toList()); }); }
原理说明
DynamoDB的KeyConditionExpression要求所有名称占位符(以#开头)必须在NameMap中有对应映射,值占位符(以:开头)必须在ValueMap中有对应值。一旦名称不匹配,对应条件片段会被忽略,导致查询仅执行#key = :key这一个条件,返回该分区键下的所有数据。修正后,BETWEEN条件会正确作用在reference字段上,筛选出指定accountId范围内的数据。
内容的提问来源于stack exchange,提问作者Jorge Guerreiro
相关产品推荐
相关产品推荐

