I’m having an issue using BatchGetCommand
to get a list of records from a DynamoDB table.
I am using an AWS Lambda that uses NodeJS 18.x.
I have been able to get ScanCommand
, GetCommand
and QueryCommand
to work.
BatchGetCommand
is giving a 400 with error message: "The provided key element does not match the schema".
My table has a partition key of sku
(String).
Is there something wrong with the line: { sku: { S: "RVR-8-F" }}
?
I’ve tried: { "sku": { S: "RVR-8-F" }}
, { "sku": { "S": "RVR-8-F" }}
, and { sku: "RVR-8-F" }
.
The following returns a 200 but with 0 data: { "sku": "RVR-8-F" }
, so is there something then wrong with: body = body.Items;
… ?
I’ve seen that I perhaps need to include my sort key. My table doesn’t have one.
I’ve also seen the same about a range key, but I’m unsure if my DynamoDB has one.
My table does have a "Global Secondary Index" of set
(String). Do I need to include that in my Key?
Here’s my code …
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, ScanCommand, GetCommand, QueryCommand, BatchGetCommand } from "@aws-sdk/lib-dynamodb";
const client = new DynamoDBClient();
const dynamo = DynamoDBDocumentClient.from(client);
const tableName = "AllinsonMTG-Stock";
export const handler = async (event, context) => {
let body;
let statusCode = 200;
const headers = {
"Content-Type": "application/json",
};
let cartItems = [];
if (event.body !== null && event.body !== undefined) {
cartItems = JSON.parse(event.body);
}
try {
switch (event.routeKey) {
case "POST /validate-cart":
body = await dynamo.send(
new BatchGetCommand({
RequestItems: {
"AllinsonMTG-Stock": {
Keys: [
{ sku: { S: "RVR-8-F" }}
],
ProjectionExpression: "sku, stock"
}
}
})
);
body = body.Items;
break;
// WORKS
// case "GET /stock":
// body = await dynamo.send(
// new ScanCommand({
// TableName: tableName
// })
// );
// body = body.Items;
// break;
// WORKS
// case "GET /stock/{set}":
// body = await dynamo.send(
// new ScanCommand({
// TableName: tableName,
// ExpressionAttributeNames: {
// "#set": "set",
// },
// ExpressionAttributeValues: {
// ":set_val": event.pathParameters.set
// },
// FilterExpression: "#set = :set_val"
// })
// );
// body = body.Items;
// break;
// WORKS
// case "POST /validate-cart":
// body = await dynamo.send(
// new GetCommand({
// TableName: tableName,
// Key: {
// sku: cartItems[0].sku,
// },
// ProjectionExpression: "sku, stock"
// })
// );
// body = body.Item;
// break;
// WORKS
// case "POST /validate-cart":
// body = await dynamo.send(
// new QueryCommand({
// KeyConditionExpression: 'sku = :sku',
// ExpressionAttributeValues: {
// ':sku': cartItems[0].sku
// },
// TableName: tableName,
// ProjectionExpression: "sku, stock"
// })
// );
// body = body.Items;
// break;
default:
throw new Error(`Unsupported route: "${event.routeKey}"`);
}
} catch (err) {
statusCode = 400;
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
2
Answers
After a lot of trial and error, I figured out the solution.
I used the status code 200 path I was following, so
{ sku: "NEO-86-NF" }
.I then had the Lambda return the entire body and not set
body = body.Items
.I noticed the response from BatchGetCommand looks like this:
So I used the following code which acts as expected ...
Yes there is, as I explained in the last question that you’re using the high level client but the low level syntax.
{ sku: "RVR-8-F" }
Make yourself familiar with this blog post: https://aws.amazon.com/blogs/database/exploring-amazon-dynamodb-sdk-clients/
Furthermore,the response is contained in
body.Responses
as mentioned here: https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html