Search code examples
amazon-dynamodbserverless-frameworkdynamodb-queriesdynamo-localamazon-dynamodb-index

DynamoDB query using secondary index, how to query with different keys


i'm using serverless framework with dynamodb [in Local]. trying to query with secondary indexed fields. goal is to query with few keys like we do in basic find queries in Mongo: {url:'<Somevalue>'} or may be like this {url:<somevalue>,ha:<somevalue>}

Table config i'm using currently:

serverless.yml

resources:
  Resources:
    TableName:
      Type: 'AWS::DynamoDB::Table'
      Properties:
        TableName: ${file(./serverless.js):Tables.TableName.name}
        BillingMode: PAY_PER_REQUEST
        AttributeDefinitions:
          - AttributeName: 'id'
            AttributeType: 'S'
          - AttributeName: 'url'
            AttributeType: 'S'
          - AttributeName: 'ha'
            AttributeType: 'S'
          - AttributeName: 'GSI_1_PK'
            AttributeType: 'S'
          - AttributeName: 'GSI_1_SK'
            AttributeType: 'S'
        KeySchema:
          - AttributeName: 'id'
            KeyType: 'HASH'
        GlobalSecondaryIndexes:
          - IndexName: 'GSI_1'
            KeySchema:
              - AttributeName: 'GSI_1_PK'
                KeyType: 'HASH'
              - AttributeName: 'GSI_1_SK'
                KeyType: 'RANGE'
            Projection:
              ProjectionType: 'ALL'
          - IndexName: 'URI_1'
            KeySchema:
              - AttributeName: 'url'
                KeyType: 'HASH'
            Projection:
              ProjectionType: 'ALL'
          - IndexName: 'HASH_1'
            KeySchema:
              - AttributeName: 'ha'
                KeyType: 'HASH'
            Projection:
              ProjectionType: 'ALL'

  Outputs:
    TableNameARN:
      Value: { 'Fn::GetAtt': [TableName, Arn] }
      Export:
        Name: ${file(./serverless.js):Exports.TableNameARN}

with this, currently i'm only able to search with id field,

Q:

1> What are the changes needs to be made to query with different fields ? [which is secondary indexed , without using id in the query]

2> How do i search with multiple attributes? [i.e : {url:<somevalue>,ha:<somevalue>}]

Query i'm using :

var params = {
    TableName: '<TableName>',
    IndexName:'URI_1',
    Key: {
      url: 'http://something.com'
    }
};
docClient.get(params, function(err, data) {
    if (err) ppJson(err); // an error occurred
    else ppJson(data); // successful response
});

Output of the query:

{
message:"One of the required keys was not given a value",
code:"ValidationException,
...
}

Solution

    • You already used GSI which allows you to use secondary indexes. But you shoud use query instead of get, it allows you to query any table or secondary index that has a composite primary key (a partition key and a sort key).
    • Just use FilterExpression and ExpressionAttributeValues, it supports u to use multiple conditions.

    var params = {
        TableName: '<TableName>',
        IndexName : 'URI_1',
        KeyConditionExpression : 'url = :url',
        FilterExpression : 'ha = :ha',
        ExpressionAttributeValues : {
          ':url': 'http://something.com',
          ':ha': 'aaaa'
        }
    };
    docClient.query(params, function(err, data) {
        if (err) console.log(err); // an error occurred
        else console.log(data); // successful response
    });

    additional

    There're three Expressions we could use to query conditions, the first two of them are used for Dynamodb.query and the last one is used for Dynamodb.updateItem or Dynamodb.putItem:

    • KeyConditionExpression - where you need to specify partition key - required - or sort key in. It can only support table key by default, if you want to use Indexes like GSI, you should use it with IndexName.
    • FilterExpression - is applied after a Query finishes, but before the results are returned and FilterExpression cannot contain partition key or sort key attributes.
    • ConditionExpression - A condition that must be satisfied in order for a conditional update to succeed.