0
votes

I've tried my first attempt on using DynamoDB after a long time using relational databases, this is now being done to update test results for later analysis, consider the following table and secondary index

12

I've been trying to get for a given testName, the test runs in a known range of revisions using the following Java code :

HashMap<String, Condition> scanMap = new HashMap<>();
scanMap.put("revision", new Condition().withComparisonOperator(ComparisonOperator.BETWEEN).withAttributeValueList(Arrays.asList(new AttributeValue("N:"+String.valueOf(minRev)), new AttributeValue("N:"+String.valueOf(maxRev)))));
scanMap.put("testName", new Condition().withComparisonOperator(ComparisonOperator.EQ).withAttributeValueList(new AttributeValue(Collections.singletonList(testName))));
DynamoDBScanExpression scanExpression = new DynamoDBScanExpression().withScanFilter(scanMap);
scanExpression.setIndexName("testName-revision-index");
List<ValidationReport> reports = getMapper().scan(ValidationReport.class, scanExpression);

I've tried to remove the "N:" with no luck. Removing the revision expression altogether return all the test runs with no limitation on the revision range

Any help would be appreciated here

1

1 Answers

1
votes

So, it seems like I was barking at the wrong tree here, trying to use Scan instead of Query :

The customer should not use ScanFilter, which is deprecated. List/Map datatypes are better suited to the new FilterExpression syntax. I suspect the problem is with the multi-value attribute with "N:" in the name; this doesn't seem close to the wire format. To use the "new" filter expressions, they should create ExpressionAttributeNames and ExpressionAttributeValues to tell the AWS SDK about the attributes for the filter, addExpressionAttributeNamesEntry and addExpressionAttributeValuesEntry.http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBScanExpression.html Also, I would be remiss if I didn't point out that Scan is absolutely not the right API action for this query; Query is the correct action. testName should be used with Query with a KeyConditionExpression to narrow the search down to the correct partition, and revision should be added to the same with the BETWEEN syntax. Scan is intended for backups and background operations, and in this case the customer's index schema can be used with Query to narrow the search. Caution them about using Scan; this is a fundamental best practice:http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/QueryAndScanGuidelines.html

So I've used Query instead :

    Map<String, AttributeValue> eav = new HashMap<String, AttributeValue>();
    eav.put(":v1", new AttributeValue().withS(testName));
    eav.put(":v2", new AttributeValue().withS(version));
    eav.put(":v3", new AttributeValue().withN(String.valueOf(minRev)));
    eav.put(":v4", new AttributeValue().withN(String.valueOf(maxRev)));

    final DynamoDBQueryExpression<ValidationReport> query = new DynamoDBQueryExpression<>();
    query.withKeyConditionExpression("testName = :v1");
    query.withFilterExpression("buildVersion = :v2 and revision BETWEEN :v3 AND :v4");
    query.setConsistentRead(false);
    query.withExpressionAttributeValues(eav);
    return getMapper().query(ValidationReport.class, query);`

Please note that when using the AttributeValue there's quite a difference between the following :

new AttributeValue().withS("SomeStringValue")
new AttributeValue().withN("SomeNumber")

Which is what I was missing