Query
Dynamode provides the ability to query your items. Query class allows you to retrieve multiple items that have the same partition key but different sort keys.
Query class acts as a build to construct your query with appropriate filters, to run it use Query.run(options?)
method.
Condition
Query is a child of Condition class, meaning that all methods listed on Condition page are also available in Query class. As example you can use Query.attribute(key)
method to filter out retrieved items.
new Query(Entity) or EntityManager.query()
Every query has to be initialized with Entity to infer its underlying properties. You can achieve this in two ways:
// Below definitions are equivalent
new Query(AllPossibleProperties);
AllPossiblePropertiesManager.query();
AllPossibleProperties is an example class that extends Entity.
Query.partitionKey(key)
This method prepares a partition key conditional expression. The key
parameter is a string, narrowed down to entity partition keys.
These properties are allowed for the AllPossibleProperties
model
AllPossiblePropertiesManager.query().partitionKey('partitionKey');
AllPossiblePropertiesManager.query().partitionKey('GSI_1_PK');
Typescript error: Argument of type '"unknownProperty"' is not assignable to parameter of type: "partitionKey" | "GSI_1_PK"
AllPossiblePropertiesManager.query().partitionKey('unknownProperty');
To complete partition key conditional you need to use .eq(value)
function.
.eq(value)
This comparison function will check if the given key is equal to the value that is passed in as a parameter.
UserManager.query().partitionKey('partitionKey').eq('1'); // Resulting in: `partitionKey = 1`
Query.sortKey(key)
This method prepares a sort key conditional expression. The key
parameter is a string, narrowed down to entity sort keys.
These properties are allowed for the AllPossibleProperties
model
AllPossiblePropertiesManager.query().sortKey('sortKey');
AllPossiblePropertiesManager.query().sortKey('GSI_1_SK');
AllPossiblePropertiesManager.query().sortKey('LSI_1_SK');
Typescript error: Argument of type '"unknownProperty"' is not assignable to parameter of type: "sortKey" | "GSI_1_SK" | "LSI_1_SK"
AllPossiblePropertiesManager.query().sortKey('unknownProperty');
To complete sort key conditional you need to use one of undermentioned functions.
UserManager.query().sortKey('sortKey'); // This condition has no impact on the final conditional
UserManager.query().sortKey('sortKey').eq('blazej'); // Adding comparison function (eq) after `sortKey(key)` method will complete the conditional. Resulting in: `sortKey = blazej`
.eq(value)
This comparison function will check if the given key is equal to the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').eq('blazej'); // Resulting in: `sortKey = blazej`
.ne(value)
This comparison function will check if the given key is not equal to the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').ne('blazej'); // Resulting in: `sortKey <> blazej`
.lt(value)
This comparison function will check if the given key is less than the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').lt('blazej'); // Resulting in: `sortKey < blazej`
.le(value)
This comparison function will check if the given key is less than or equal to the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').le('blazej'); // Resulting in: `sortKey <= blazej`
.gt(value)
This comparison function will check if the given key is greater than the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').gt('blazej'); // Resulting in: `sortKey > blazej`
.ge(value)
This comparison function will check if the given key is greater than or equal to the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').ge('blazej'); // Resulting in: `sortKey >= blazej`
.beginsWith(value)
This comparison function will check if the given key is begins with the value that is passed in as a parameter.
UserManager.query().sortKey('sortKey').beginsWith('bla'); // Resulting in: `begins_with(sortKey, bla)`
.between(value1, value2)
This comparison function will check if the given key is between the values that were passed in as parameters.
UserManager.query().sortKey('sortKey').between('bla', 'cla'); // Resulting in: `sortKey BETWEEN 'bla' AND 'cla'`
Query.indexName(name)
The name of a secondary index to query. This index can be any local secondary index or global secondary index. The name
parameter is a string, narrowed down to entity index names. It uses DynamoDB's IndexName
.
UserManager.query().partitionKey('partitionKey').eq('1').indexName('LSI_1_NAME') // Resulting in: `IndexName: LSI_1_NAME`
Query.sort(order)
This method sorts the items you receive by using sort key. It uses DynamoDB's ScanIndexForward
.
The order
parameter must be a string, either 'ascending'
or 'descending'
. Query will return items in ascending order by default.
UserManager.query().partitionKey('partitionKey').eq('1').sort('descending'); // Resulting in: `ScanIndexForward: false`
Query.limit(count)
This method will limit the number of items that DynamoDB query in one request. It uses DynamoDB's Limit
.
Unlike most SQL databases this does not guarantee the response will contain 5 items. DynamoDB will only query a maximum of 5 items and check if they match and should be returned.
The count
argument should be a number
representing how many items you wish DynamoDB to query.
UserManager.query().partitionKey('partitionKey').eq('1').limit(10); // Resulting in: `Limit: 10`
Query.startAt(key)
In case there are more items to retrieve in a previous query response, Dynamode will return lastKey
property with primary key of last evaluated item. You can pass this property to further query your items. It uses DynamoDB's LastEvaluatedKey
.
const response1 = await UserManager.query().partitionKey('partitionKey').eq('1').run();
const response2 = await UserManager.query().partitionKey('partitionKey').eq('1').startAt(response1.lastKey).run(); // Resulting in: `LastEvaluatedKey: response1.lastKey`
Query.consistent()
This will cause the query to run a consistent read. By default read is eventually consistent. It uses DynamoDB's ConsistentRead
.
UserManager.query().partitionKey('partitionKey').eq('1').consistent(); // Resulting in: `ConsistentRead: true`
Query.count()
Instead of returning an array of items, this method will make the query operation to return an object with count information. This option saves bandwidth by using DynamoDB's Select
.
UserManager.query().partitionKey('partitionKey').eq('1').count(); // Resulting in: `Select: 'COUNT'`
Query.attributes(attributes)
This method is used to tag what item attributes should be retrieved and returned. This uses DynamoDB's ProjectionExpression
.
If this value is undefined
, then all attributes will be returned. attributes
argument should be an array of strings representing the property names to return.
UserManager.query().partitionKey('partitionKey').eq('1').attributes(['username', 'age']); // Resulting in: `ProjectionExpression: 'username, age'`
Query.run(options?)
Description
This method is used to execute constructed query and retrieve multiple items from DynamoDB. It uses the Query DynamoDB operation.
By default it makes one DynamoDB API call, but you can change it by passing all
option described below. With all
set to true
this function will send continuous query requests until all items are retrieved.
Arguments
You can add optional options
parameter that is an object. The table below represents options that you can pass in:
Name | Description | Type | Default |
---|---|---|---|
return | What the method should return. For 'default' method returns initialized classes with retrieved data. For 'input' method returns prepared DynamoDB input command and no request is made to DynamoDB (method no longer returns a promise). For 'output' method returns the bare output from DynamoDB operation. | 'default' | 'input' | 'output' | 'default' |
all | In case it is set to true this method will send continuous query requests until all items are retrieved (it checks lastKey property from previous responses). This can be useful for getting all items autonomously in case you don't want to check lastKey property manually and send multiple requests yourself. | boolean | false |
max | Use only if all option is set to true . The maximum number of items that should be retrieved, regardless if the lastKey property still exists in the response. As default an unlimited number of items will be retrieved to the point that lastKey property no longer exists. | number | Infinity |
delay | Use only if all option is set to true . Number of milliseconds to delay between receiving a response to the next query request. | number | 0 |
extraInput | Extra input that is passed to QueryInput DynamoDB operation. Use it only in case that you know what are you are doing as it may override other properties passed to DynamoDB operation. | QueryInput | undefined |
If all
option is set to true
all of the requests will be merged into a single array. count
and scannedCount
properties will be summed in the response. If you pass max
option and there is still a lastKey
in the response it will be returned to you.
Examples
- return: 'default'
- return: 'input'
- return: 'output'
const result = await UserManager.query()
.partitionKey('partitionKey').eq('1')
.sortKey('sortKey').beginsWith('bla')
.limit(1).sort('descending')
.run();
// OR
const result = await UserManager.query()
.partitionKey('partitionKey').eq('1')
.sortKey('sortKey').beginsWith('bla')
.limit(1).sort('descending')
.run({ return: 'default' });
Output:
{
items: [
User {
dynamodeEntity: 'User',
partitionKey: '1',
sortKey: 'blazej3',
username: 'blazej',
email: 'blazej@gmail.com',
age: 18,
friends: [Array],
config: [Object]
}
],
count: 1,
scannedCount: 1,
lastKey: { partitionKey: '1', sortKey: 'blazej3' }
}
const input = UserManager.query()
.partitionKey('partitionKey').eq('1')
.sortKey('sortKey').beginsWith('bla')
.limit(1).sort('descending')
.run({ return: 'input' });
Output:
{
TableName: 'users',
Limit: 1,
ScanIndexForward: false,
KeyConditionExpression: 'partitionKey = :partitionKey AND begins_with(sortKey, :sortKey)',
FilterExpression: undefined,
ExpressionAttributeNames: undefined,
ExpressionAttributeValues: { ':partitionKey': { S: '1' }, ':sortKey': { S: 'bla' } }
}
const output = await UserManager.query()
.partitionKey('partitionKey').eq('1')
.sortKey('sortKey').beginsWith('bla')
.limit(1).sort('descending')
.run({ return: 'output' });
Output:
{
'$metadata': {
...
},
ConsumedCapacity: undefined,
Count: 1,
Items: [
{
dynamodeEntity: [Object],
sortKey: [Object],
partitionKey: [Object],
config: [Object],
email: [Object],
age: [Object],
friends: [Object],
username: [Object]
}
],
LastEvaluatedKey: { partitionKey: { S: '1' }, sortKey: { S: 'blazej3' } },
ScannedCount: 1
}