DynamoDB QueryCommand in AWS SDK JS v3
Tags: aws, node, programming, tutorial
Published: 2022-10-28 08:58:21

The AWS SDK for JavaScript v3 introduces the concept of modular architecture which encapsulates each service into a separate package. It means that you no longer need to import the whole AWS SDK package, but only the services that you need to use. This significantly reduces the size of your application.

It also comes with a new middleware stack to control the lifecycle of an operation call and TypeScript support. You can [read more about it here](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html).

Despite the nice features, migrating from v2 to v3 comes with some complexity that we'd like to highlight.

## Marshalled/Unmarshalled data
The data that is sent as input to a given DynamoDb command must be marshalled. Marshalling is simply adding the type of the value to the JSON object

JSON object:

```javascript
ExpressionAttributeValues: {
  ':username': 'somename',
  ':email': 'some@name.com'
},
```

Marshalled JSON object:

```javascript
ExpressionAttributeValues: {
  ':username': {S: 'somename'},
  ':email': {S: 'some@name.com'}
},
```

Respectively, the command's response must be unmarshalled.

## Examples
The examples are based on the assumption that we have a `users` table that has a partition key called `username` and sort key - `email`.

_Note: The AWS credentials are not covered in the examples below._

### Example 1: Send a query command with manually marshalled data.

1. Import `DynamoDBClient` and `QueryCommand` modules from `@aws-sdk/client-dynamodb`
2. The `QueryCommand` expects `ExpressionAttributeValues` to be a marshalled JSON object, so we explicitly set the type of the values
3. The commands are executed by using the `send` method of the `DynamoDBClient` which accepts the command as the first argument.

```javascript
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";

export const dynamoDbClient = new DynamoDBClient({region: 'eu-central-1'});

// The ExpressionAttributeValues must be marshalled,
// so the type of the values are explicitly set.
const params = {
  TableName: 'users',
  KeyConditionExpression: 'username = :username and email = :email',
  ExpressionAttributeValues: {
    ':username': {S: 'somename'},
    ':email': {S: 'some@name.com'}
  },
};

try {
  const response = await dynamoDbClient.send(new QueryCommand(params));
}
catch (e) {
  console.error(e.message);
}
```

### Example 2: Send a query command by using a utility module to marshall/unmarshall the data.

Instead of explicitly specifying the type of the values for the `ExpressionAttributeValues` key, we can use the `marshall`/`unmarshall` modules that come from the [@aws-sdk/util-dynamodb](https://www.npmjs.com/package/@aws-sdk/util-dynamodb) package.

```javascript
import { DynamoDBClient, QueryCommand } from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';

export const dynamoDbClient = new DynamoDBClient({region: 'eu-central-1'});

// The ExpressionAttributeValues must be marshalled,
// so the type of the values are explicitly set.
const params = {
  TableName: 'users',
  KeyConditionExpression: 'username = :username and email = :email',
  ExpressionAttributeValues: marshall({
    ':username': 'somename',
    ':email': 'some@name.com'
  }),  
};

try {
  const response = await dynamoDbClient.send(new QueryCommand(params));
}
catch (e) {
  console.error(e.message);
}
```

### Example 3: Send a query command by using `@aws-sdk/lib-dynamodb`

The [@aws-sdk/lib-dynamodb](https://www.npmjs.com/package/@aws-sdk/lib-dynamodb) automatically handles the necessary marshalling and unmarshalling of the data.

The only difference is that the `QueryCommand` is imported from the `@aws-sdk/lib-dynamodb` package instead of `@aws-sdk/client-dynamodb` and no manual marshalling is needed.

```javascript
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { QueryCommand } from '@aws-sdk/lib-dynamodb';

export const dynamoDbClient = new DynamoDBClient({region: 'eu-central-1'});

// The ExpressionAttributeValues will be automatically
// marshalled by the @aws-sdk/lib-dynamodb.
const params = {
  TableName: 'users',
  KeyConditionExpression: 'username = :username and email = :email',
  ExpressionAttributeValues: {
    ':username': 'somename',
    ':email': 'some@name.com'
  },
};

try {
  const response = await dynamoDbClient.send(new QueryCommand(params));
}
catch (e) {
  console.error(e.message);
}
```

## Bottom line

The **AWS SDK for JavaScript v3** introduces the ES6 modules which can reduce the size of our applications. It also comes with some nice features like a new middleware stack and TypeScript support, however, migrating from v2 to v4 might be a bit tricky and requires code changes.