0

I am creating a REST service using springboot and DynamoDB as database. I have a StudentDTO class with the following fields and Subject class which has subjects info as (key,value pair) :

@DynamoDBTable(tableName="Students")
Class Students{

@DynamoDBHashKey(attributeName="id")
int id;
String name;
int year;
@DynamoDBAttribute(attributeName="subjects")
List<Subjects> subjects; //it has serializedName("subjects")
//getter and setters 
}

@DynamoDBDocument
Class Subjects{
String key;
String value;
}

I have some criteria on which i need to fetch the data. These criteria may vary. Below are some example :

  1. Can fetch data on name, id ("id":1,"name":"joe")
  2. Can fetch data on name, subject info ("name":"joe",subjects:"[{"key":"S1","value":"Geography"},{"key":"S2","value":"History"}]")
  3. May want data on name, year

There is no fixed combination of criteria on which I can build my query. I tried using DynamoDBScanExpression but not able to identify how to set the filterExpression.

Created a map of (key,value) like (,)

I can create the attributeName and attributeValue like (all in DynamoDBDAO.java) :

 Map<String, String> attributeNames = new HashMap<String, String>();
    Map<String, AttributeValue> attributeValues = new HashMap<String, AttributeValue>();
 StringJoiner filterExpression = new StringJoiner(" AND ");

    if (null != json.getS_no()) {
        StringBuilder expression = new StringBuilder();
        attributeNames.put("#s_no", "s_no");
        attributeValues.put(":sno", new AttributeValue().withN(json.getS_no()));
        expression.append("#s_no").append(" ").append("<>").append(" ").append(":s_no");
        filterExpression.add(expression);
    }
    if (null != json.getName()) {
        StringBuilder expression = new StringBuilder();
        attributeNames.put("#name", "name");
        attributeValues.put(":name", new AttributeValue().withN(json.getName()));
        expression.append("#name").append(" ").append("<>").append(" ").append(":name");
        filterExpression.add(expression);
    }

    if(null != json.getSubjects()){
        StringBuilder expression = new StringBuilder();
        attributeNames.put("#subjects", "subjects");
        attributeValues.put(":subjects", new AttributeValue().withS(map.keySet().toString()));

        expression.append("#subjects").append(" ").append("IN").append(" ").append(":subjects");
    }
    ...
    and so on

scan query

  DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
        .withFilterExpression(filterExpression.toString()) // HERE CONDITION CAN CHANGE ACCORDING TO THE ATTRIBUTES IN THE INPUT.
        .withExpressionAttributeNames(attributeNames)
        .withExpressionAttributeValues(attributeValues);

  List<DBMapper> records = Dynamomapper.scan(DBMapper.class, scanExpression);

But in SCAN() function it given exception :

 com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException:Students[subjects]; could not unconvert subjects
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperTableModel.unconvert(DynamoDBMapperTableModel.java:271)
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.privateMarshallIntoObject(DynamoDBMapper.java:456)
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.marshallIntoObjects(DynamoDBMapper.java:484)
at com.amazonaws.services.dynamodbv2.datamodeling.PaginatedScanList.<init>(PaginatedScanList.java:64)
at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.scan(DynamoDBMapper.java:1458)
at com.amazonaws.services.dynamodbv2.datamodeling.AbstractDynamoDBMapper.scan(AbstractDynamoDBMapper.java:216)
at com.example.dynamodb.dao.DynamoDBDAO.findByAttributes(DynamoDBDAO.java:379)

Please suggest.

A.P
  • 53
  • 3
  • 12
  • I got the solution for appending the filter expressions but nested document is not able to unconvert. Need suggestions – A.P Apr 05 '18 at 07:45

2 Answers2

0

It looks like you're missing @DynamoDBAttribute on the attributes in the Subjects class.

Changing your Subjects class to the following should allow it to be deserialized correctly:

@DynamoDBDocument
class Subjects {
    @DynamoDBAttribute(attributeName="key")
    String key;

    @DynamoDBAttribute(attributeName="value")
    String value;

    // Getters/setters
}

Also, if you're planning on fetching the name and year attributes, you'll probably want to add @DynamoDBAttribute to the name and year fields in the Students class too.

Tom
  • 1,660
  • 8
  • 16
0

Solution I got is by adding No Argument parameter to this POJO

A.P
  • 53
  • 3
  • 12