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:
GSI:
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));
Hash key in DynamoDB The primary reason for that complexity is that you cannot query DynamoDB without the hash key. So, it's not allowed to query the entire database. That means you cannot do what you would call a full table scan in other databases.
In Amazon DynamoDB, you can use either the DynamoDB API, or PartiQL, a SQL-compatible query language, to query an item from a table. With Amazon DynamoDB the Query action lets you retrieve data in a similar fashion. The Query action provides quick, efficient access to the physical locations where the data is stored.
There are two types of primary keys in DynamoDB: Partition key: This is a simple primary key. If the table has only a partition key, then no two items can have the same partition key value. Composite primary key: This is a combination of partition key and sort key.
You can not query only using a Sort Key. You need to specify a partition key to perform query operations. Else, you need to create a global secondary index or perform a scan operation.
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)); } });
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; } } });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With