Skip to main content

QueryCommand

Performs a Query Operation on a Table:

import { QueryCommand } from 'dynamodb-toolbox/table/actions/query'

const queryCommand = PokeTable.build(QueryCommand)

const params = queryCommand.params()
const { Items } = await queryCommand.send()

Request

.query(...)

(required)

The partition to query, with optional index and range condition:

  • partition: The partition key to query
  • index (optional): The name of a secondary index to query
  • range (optional): If the table or index has a sort key, an additional Range or Equality Condition
// Get 'ashKetchum' pokemons
await PokeTable.build(QueryCommand)
.query({ partition: 'ashKetchum' })
.send()

You can use the Query type to explicitly type an object as a QueryCommand query object:

import type { Query } from 'dynamodb-toolbox/table/actions/query'

// Get 'ashKetchum1' pokemons with a level ≥ 50
const query: Query<typeof PokeTable> = {
index: 'byTrainerId',
partition: 'ashKetchum1',
range: { gte: 50 }
}

const { Items } = await PokeTable.build(QueryCommand)
.query(query)
.send()

.entities(...)

Provides a list of entities to filter the returned items (via the internal entity attribute). Also formats them and types the response:

// 👇 Typed as (Pokemon | Trainer)[]
const { Items } = await PokeTable.build(QueryCommand)
.query(query)
.entities(PokemonEntity, TrainerEntity)
.send()

Returned items are also tagged with their respective entity names through the $entity symbol:

import { $entity } from 'dynamodb-toolbox/table/actions/query'

const { Items = [] } = await queryCommand.send()

for (const item of Items) {
switch (item[$entity]) {
case "pokemon":
// 🙌 Typed as Pokemon
...
case "trainer":
// 🙌 Typed as Trainer
...
}
}

.options(...)

Provides additional options:

const { Items } = await PokeTable.build(QueryCommand)
.options({
consistent: true,
limit: 10
...
})
.send()

You can use the QueryOptions type to explicitly type an object as a QueryCommand options object:

import type { QueryOptions } from 'dynamodb-toolbox/table/actions/query'

const queryOptions: QueryOptions<
typeof PokeTable,
// 👇 Optional entities
[typeof PokemonEntity, typeof TrainerEntity]
> = {
consistent: true,
limit: 10,
...
}

const { Items } = await PokeTable.build(QueryCommand)
.query(query)
.entities(PokemonEntity, TrainerEntity)
.options(queryOptions)
.send()
info

It is advised to provide entities and query first as they constrain the options type.

Available options (see the DynamoDB documentation for more details):

Cat.OptionTypeDefaultDescription
Generalconsistentbooleanfalse

By default, read operations are eventually consistent (which improves performances and reduces costs).

Set to true to use strongly consistent reads (unavailable on secondary indexes).

reversebooleanfalse

Specifies the order for index traversal.

By default, the traversal is performed in ascending order. If set to true, the traversal is performed in descending order.

capacityCapacityOption"NONE"

Determines the level of detail about provisioned or on-demand throughput consumption that is returned in the response.

Possible values are "NONE", "TOTAL" and "INDEXES".

tableNamestring-

Overrides the Table name. Mostly useful for multitenancy.

Paginationlimitinteger ≥ 1-

The maximum number of items to evaluate

Note that DynamoDB may return a lower number of items if it reaches the limit of 1MB, or if filters are applied.

Applies for each page if maxPages is used.

exclusiveStartKeyKey-The primary key of the first item that this operation evaluates. Use the LastEvaluatedKey from the previous operation.
maxPagesinteger ≥ 11

A "meta" option provided by DynamoDB-Toolbox to send multiple requests in a single promise.

Note that Infinity is a valid (albeit dangerous) option.

If two pages or more have been fetched, the responses Count and ScannedCount are summed, but the ConsumedCapacity is omitted for the moment.

FiltersselectSelectOption-

The strategy for returned attributes. You can retrieve all attributes, specific attributes, the count of matching items, or in the case of an index, some or all of the projected attributes.

Possible values are "ALL_ATTRIBUTES", "ALL_PROJECTED_ATTRIBUTES" (if index is specified), "COUNT" and "SPECIFIC_ATTRIBUTES" (if attributes are specified)

filtersRecord<string, Condition>-

For each entity name, a condition that must be satisfied in order for evaluated items of this entity to be returned (improves performances but does not reduce costs).

Requires entities.

See the ConditionParser action for more details on how to write conditions.

filterCondition-

An untyped condition that must be satisfied in order for evaluated items to be returned (improves performances but does not reduce costs).

No effect if entities are provided (use filters instead).

See the ConditionParser action for more details on how to write conditions.

attributesstring[]-

To specify a list of attributes to retrieve (improves performances but does not reduce costs).

Requires entities. Paths must be common to all entities.

See the PathParser action for more details on how to write attribute paths.

entityAttrFilterbooleantrue

By default, specifying entities introduces a Filter Expression on the entity internal attribute. Set this option to false to disable this behavior.

This option is useful for querying items that miss the entity internal attribute (e.g. when migrating to DynamoDB-Toolbox). You can use Middleware Stacks to introduce it manually.

Note that this can result in types being wrongly inferred, so be extra careful.

Examples
const { Items } = await PokeTable.build(QueryCommand)
.query({ partition: 'ashKetchum' })
.entities(PokemonEntity)
.options({ consistent: true })
.send()
Paginated
let lastEvaluatedKey: Record<string, unknown> | undefined
const command = PokeTable.build(QueryCommand).query({
partition: 'ashKetchum'
})

do {
const page = await command
.options({ exclusiveStartKey: lastEvaluatedKey })
.send()

// ...do something with page.Items here...

lastEvaluatedKey = page.LastEvaluatedKey
} while (lastEvaluatedKey !== undefined)
Filtered
const { Items } = await PokeTable.build(QueryCommand)
.query({ partition: 'ashKetchum' })
.entities(PokemonEntity, TrainerEntity)
.options({
filters: {
POKEMONS: { attr: 'pokeType', eq: 'fire' },
TRAINERS: { attr: 'age', gt: 18 }
}
})
.send()

Response

The data is returned using the same response syntax as the DynamoDB Query API.

If entities have been provided, the response Items are formatted by their respective entities.

You can use the QueryResponse type to explicitly type an object as a QueryCommand response object:

import type { QueryResponse } from 'dynamodb-toolbox/table/actions/query'

const queryResponse: QueryResponse<
typeof PokeTable,
// 👇 Query
{ partition: 'ashKetchum' },
// 👇 Optional entities
[typeof PokemonEntity],
// 👇 Optional options
{ attributes: ['name', 'type'] }
> = { Items: ... }