I have the following data
Partition key | Sort key | value |
---|---|---|
aa | str1 | 1 |
aa | str2 | 123 |
aa | str3 | 122 |
ab | str1 | 12 |
ab | str3 | 111 |
ac | str1 | 112 |
And by using QueryRequest
I want to select entries where the partition key is "aa" and the sort key is either "str1" or "str3". I have tried to create a Condition
, but nothing works with different exceptions, so could someone point out how this query can be written?
var pkCondition = new Condition
{
ComparisonOperator = ComparisonOperator.EQ,
AttributeValueList =
{
new AttributeValue { S = "aa" },
},
};
// Exception One or more parameter values were invalid: Condition parameter type does not match schema type
var skCondition1 = new Condition
{
ComparisonOperator = ComparisonOperator.EQ,
AttributeValueList =
{
new AttributeValue { SS = { "str1", "str3" } },
},
};
// Exception: One or more parameter values were invalid: Invalid number of argument(s) for the EQ ComparisonOperator
var skCondition2 = new Condition
{
ComparisonOperator = ComparisonOperator.EQ,
AttributeValueList =
{
new AttributeValue { S = "str1" },
new AttributeValue { S = "str3" },
},
};
// Well this one is clear because IN cannot be performed on keys
// Exception: One or more parameter values were invalid: ComparisonOperator IN is not valid for SS AttributeValue type
var skCondition3 = new Condition
{
ComparisonOperator = ComparisonOperator.IN,
AttributeValueList =
{
new AttributeValue { SS = { "str1", "str3" } },
},
};
// Works, but not what I need
var skCondition4 = new Condition
{
ComparisonOperator = ComparisonOperator.EQ,
AttributeValueList =
{
new AttributeValue { S = "str1" },
},
};
return new QueryRequest
{
TableName = "My table",
KeyConditions =
{
{ "Partition key", pkCondition },
{ "Sort key", skCondition },
},
};
After some research I have found out that KeyConditionExpression
can also be used, but I have not found any combination that could work for my case.
// Exception: Invalid operator used in KeyConditionExpression: OR
const string keyConditionExpression1 = "#pk = :pkval AND (#sk = :sk1 OR #sk = :sk2)";
// Exception: Invalid operator used in KeyConditionExpression: IN
const string keyConditionExpression2 = "#pk = :pkval AND #sk IN (:sk1, :sk2)";
new QueryRequest
{
TableName = "My table",
KeyConditionExpression = keyConditionExpression,
ExpressionAttributeNames = new Dictionary<string, string>
{
{ "#pk", "Partition key" },
{ "#sk", "Sort key" },
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{ ":pkval", new AttributeValue { S = "aa" } },
{ ":sk1", new AttributeValue { S = "str1" } },
{ ":sk2", new AttributeValue { S = "str3" } },
},
};
Next, I have also tried using FilterExpression
where IN and OR are allowed, but again there was another exception: Filter Expression can only contain non-primary key attributes
.
new QueryRequest
{
TableName = "My table",
KeyConditionExpression = "#pk = :pkval",
FilterExpression = "#sk IN (:sk1, :sk2)",
ExpressionAttributeNames = new Dictionary<string, string>
{
{ "#pk", "Partition key" },
{ "#sk", "Sort key" },
},
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{ ":pkval", new AttributeValue { S = "aa" } },
{ ":sk1", new AttributeValue { S = "str1" } },
{ ":sk2", new AttributeValue { S = "str3" } },
},
};
2
Answers
Based on Leeroy's answer there is a C# code that can make the request:
DynamoDB data structure can be likened to a B-tree. That is to say that an efficient Query reads only a contiguous piece of data.
You have an access pattern where you cannot guarantee that the data is contiguous and stored beside each other on disk. It’s for that reason you are struggling.
Possible Solutions
Depending on the actual data you store in your sort key, you can do a
between
orbegins_with
condition. `WHERE SK between(str1,str3).However your access pattern seems to suggest that you have specific sort keys you need that do not follow a pattern, in which case you should us a
BatchGetItem
which will allow you to fetch up to 100 items per request.If the full value of the sort key is unknown, then you can do an
ExecuteStatement
request which will execute multiple Query calls under the hood fulfilling your access pattern.