1
votes

I have a table with hash and range primary key. I need to query by eventDate and customerId. Here is the structure. Hash is an uniqueId formatted like UUID, range is a customerId. Also I have LSI with range key eventDate. I want to make a query with param:

'KeyConditionExpression' => "customerId = :customer_id"

But I got an error:

Query condition missed key schema element: uniqueId

You may say I shouldn't use useless hashes but what should I do then? Before that I tried to use hash and range customerId, eventDate but I was not able to use them since it is not guaranted that eventDate will be unique. This means if three events were generated at the same time then only the last one was saved.

Is there a way to combine such structure with dynamodb?

1

1 Answers

1
votes

You can do one of the following:

  1. Make Customer ID as HashKey and UUID as RangeKey. Then, the LSI would be defined on CustomerID and EventDate. You can search the table on LSI as follows:

    // Using DynamoDBMapper in AWS SDK Java
    DynamoDBQueryExpression<YourClass> query = 
        new DynamoDBQueryExpression<YourClass>();
    YourClass hashKeyValues = new YourClass();
    hashKeyValues.setCustomerId(customerId);
    
    Map<String, Condition> rangeKeyConditions = 
        new HashMap<String, Condition>();
    rangeKeyConditions.put("EventDate", 
        new Condition()
            .withConditionalOperator(ConditionalOperator.EQ)
            .withAttributeValue(new AttributeValue(eventDate)));
    
    query.setHashKeyValues(hashKeyValues);
    query.setRangeKeyConditions(rangeKeyConditions);
    query.setIndexName(LSI_CUSTOMER_ID_EVENT_DATE);
    // Execute the query using DynamoDBMapper.
    
  2. Create a Global Secondary Index(GSI) on the CustomerID as the HashKey and EventDate as the RangeKey of the GSI.

    // Using DynamoDBMapper in AWS SDK Java
    DynamoDBQueryExpression<YourClass> query = 
        new DynamoDBQueryExpression<YourClass>();
    YourClass hashKeyValues = new YourClass();
    hashKeyValues.setCustomerId(customerId);
    
    Map<String, Condition> rangeKeyConditions = 
        new HashMap<String, Condition>();
    rangeKeyConditions.put("EventDate", 
        new Condition()
            .withConditionalOperator(ConditionalOperator.EQ)
            .withAttributeValue(new AttributeValue(eventDate)));
    
    query.setHashKeyValues(hashKeyValues);
    query.setRangeKeyConditions(rangeKeyConditions);
    query.setIndexName(GSI_CUSTOMER_ID_EVENT_DATE);
    // Execute the query using DynamoDBMapper.
    

You may be aware of the cost of using a GSI, if not you may want to check the GSI documentation once.

HTH.