-1

I have a dynamo db table CustomerOrders with following fields

  1. Primary partition key: CustomerId (Number)
  2. Primary sort key: DepartmentId (Number)
  3. Order (Serialized Json String)

I would like to do a query on multiple customers in one request without using Sort Key (DepartmentId). So I created a Global Secondary Index on CustomerId and would like to use that to query just using the CustomerId. I see documentation only related to BatchGetItemAsync for running batch queries. I don't see a way to set the IndexName on a BatchGetItemRequest. How can that be done?

Below is my code segment so far:

public async Task<List<CustomerOrder>> GetOrdersAsync(List<int> customerIds)
{
    var orders = new List<CustomerOrder>();

    var tableKeys = new List<Dictionary<string, AttributeValue>>();
    foreach (var x in customerIds)
    {
        tableKeys.Add(new Dictionary<string, AttributeValue> { { "CustomerId", new AttributeValue { N = x.ToString() } } });
    }

    var dynamoTable = $"CustomerOrders";

    var keysAndAttributes = new KeysAndAttributes
    {
        AttributesToGet = new List<string> { "CustomerId", "DepartmentId", "Order" },
        Keys = tableKeys                
    };

    var request = new BatchGetItemRequest
    {
        ReturnConsumedCapacity = ReturnConsumedCapacity.INDEXES, // Not sure what this does
        RequestItems = new Dictionary<string, KeysAndAttributes> { { dynamoTable, keysAndAttributes } }
    };

    BatchGetItemResponse result;
    do
    {
        result = await dynamoDbClient.BatchGetItemAsync(request); // Exception gets thrown from here

        var responses = result.Responses;
        foreach (var tableName in responses.Keys)
        {
            var tableItems = responses[tableName];
            foreach (var item in tableItems)
            {
                orders.Add(new CustomerOrder
                {
                    CustomerId = int.Parse(item["CustomerId"].N),
                    DepartmentId = int.Parse(item["DepartmentId"].N),
                    Order = JsonConvert.DeserializeObject<Order>(item["Order"].S)
                });
        }
    }

    //  Set RequestItems to the result's UnprocessedKeys and reissue request
    request.RequestItems = result.UnprocessedKeys;

    } while (result.UnprocessedKeys.Count > 0);

    return orders;
}

I am getting The provided key element does not match the schema error with the above code. Please help!

user007
  • 1,504
  • 2
  • 18
  • 51

1 Answers1

1

You can't "set the IndexName on a BatchGetItemRequest"

In fact, you can't GetItem() on a GSI/LSI either. GetItem() only works on the table.

And GetItem() always requires the full primary key.

With a partial key, you'd need to perform multiple Query(), one for each hash key.

The GSI isn't doing anything for you. Department as a sort key really isn't doing anything for you either since I assume customerId is unique.

A better structure might have been to have the table defined with only hash key for the primary key;

Charles
  • 21,637
  • 1
  • 20
  • 44
  • This is an existing table. I am trying to make it work using GSI and going by your comments I can't. The CustomerId is unique, though. So I was thinking GSI would be a solution. Looks like threads and Query combo are the options. Let me talk to the team which owns this table and I hope they can remove that sort key. – user007 Apr 20 '21 at 18:04