27
votes

I need to query a DynamoDB table by a key different than its Primary Key. I tried to create a Global Secondary Index for it. However I get this error: "query key condition not supported dynamodb". By seeing some examples, it looks like I can't query by a secondary index unless I also include the primary index/key, is this correct? Let's say I need to query by all employees that work in a certain city, can I do that without the employeeID?

Updated info Maybe my index is not created as it should?

Table info:

  • id-->Primary partition key
  • primary sort key-->name

GSI:

  • Partition Key/primary key--> city
  • Projected-->All

When I query from node I sent as a parameter the city, and the index name:

    const filter = { city: city};
    return this.getRecordsFromDb(filter, { IndexName: "myIndexName" })
        .then(records => __.head(records));
2
You can create and query the GSI without the partition key of the main table. Can you show your code where you are trying to query the GSI? Please mention the key attributes of GSI as well.notionquest
Thanks! I'll update the question with my codejoeCarpenter

2 Answers

33
votes

Note:- As you have not provided the full code, it is difficult to simulate and identify the issue. However, I have created the similar tables and indexes. It works fine for me. You can refer the below code for more details.

Here is the table create script and query the index.

You can change the table name and index name if required. I have followed the same key attributes structure that you have mentioned on post.

This has been tested and working fine.

1) Create table 'city' with index 'city_index':-

var params = {
        TableName: 'city',
        KeySchema: [ // The type of of schema.  Must start with a HASH type, with an optional second RANGE.
            { // Required HASH type attribute
                AttributeName: 'id',
                KeyType: 'HASH',
            },
            { // Required HASH type attribute
                AttributeName: 'name',
                KeyType: 'RANGE',
            }            

        ],
        AttributeDefinitions: [ // The names and types of all primary and index key attributes only
            {
                AttributeName: 'id',
                AttributeType: 'S', // (S | N | B) for string, number, binary
            },
            {
                AttributeName: 'name',
                AttributeType: 'S', // (S | N | B) for string, number, binary
            },
            {
                AttributeName: 'city',
                AttributeType: 'S', // (S | N | B) for string, number, binary
            },

        ],
        ProvisionedThroughput: { // required provisioned throughput for the table
            ReadCapacityUnits: 400, 
            WriteCapacityUnits: 400, 
        },
        GlobalSecondaryIndexes: [ // optional (list of GlobalSecondaryIndex)
            { 
                IndexName: 'city_index', 
                KeySchema: [
                    { // Required HASH type attribute
                        AttributeName: 'city',
                        KeyType: 'HASH',
                    }
                ],
                Projection: { // attributes to project into the index
                    ProjectionType: 'ALL' // (ALL | KEYS_ONLY | INCLUDE)
                },
                ProvisionedThroughput: { // throughput to provision to the index
                    ReadCapacityUnits: 400,
                    WriteCapacityUnits: 400,
                },
            },
            // ... more global secondary indexes ...
        ],

    };
    dynamodb.createTable(params, function(err, data) {
        if (err){ console.log("error :" +JSON.stringify(err));} // an error occurred
        else console.log("success :" +JSON.stringify(data)); // successful response

    });

2) Insert some data to city table

3) Query using index:-

var docClient = new AWS.DynamoDB.DocumentClient();
var table = "city";
var params = {
    TableName : table,
    IndexName : 'city_index',
    KeyConditionExpression : 'city = :cityVal', 
    ExpressionAttributeValues : {
        ':cityVal' : 'london'        
    }
};

docClient.query(params, function(err, data) {
    if (err) {
        console.error("Unable to read item. Error JSON:", JSON.stringify(err,
                null, 2));
    } else {
        console.log("GetItem succeeded:", JSON.stringify(data, null, 2));
    }
});
2
votes

This is my implementation with Node.js (of querying by another field) with scan:

  var params = {
    TableName: 'TableName',
    FilterExpression: 'AnotherFieldName = :email',
    ExpressionAttributeValues: {
      ":email": { S: emailISearchFor }  
    }
  };

  ddb.scan(params, function(err, data){
    if(err){
      ...
    } else {

      if(data.Items.length > 0){ // here is the info
        valueIWant = data.Items[0].PrimaryKeyName.S;
      }

    }

  });