skip to Main Content

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


  1. Chosen as BEST ANSWER

    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:

    enter image description here

    So I used the following code which acts as expected ...

    case "POST /validate-cart":
      body = await dynamo.send(
        new BatchGetCommand({
          RequestItems: {
            "AllinsonMTG-Stock": {
              Keys: [
                { sku: "NEO-86-NF" },
                { sku: "NEO-193-NF" }
              ],
              ProjectionExpression: "sku, stock"
            }
          }
        })
      );
      body = body['Responses']['AllinsonMTG-Stock'];
      break;
    

  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search