I have a table in DynamoDB that has a key schema like this:
class MyTableKeySchemaT(TypedDict):
pkey: str # HASH
id: int # RANGE
The id in this table is a serially increasing integer.
I have a use case where I query this table to obtain the maximum id. My query looks like this:
def get_max_id(pkey: str) -> int:
table = self._get_table("my-table")
response = table.query(
Select="SPECIFIC_ATTRIBUTES",
Limit=1,
KeyConditionExpression=Key('pkey').eq(pkey),
ProjectionExpression="id",
ScanIndexForward=False,
ConsistentRead=True,
)
if len(response["Items"]) == 0:
return -1
return response["Items"][0]["id"]
This is fairly straightforward operation: Read the table in reverse sorted order and return the first item.
In my use-case, I have a process that periodically calls this function for a given pkey, and I am observing that the query for the same pkey will occasionally not return anything (hence the -1):
get_max_id("customer1") -> 7564
get_max_id("customer1") -> 7565
get_max_id("customer1") -> -1
get_max_id("customer1") -> 7566
get_max_id("customer1") -> 7567
If I print out details from the response I see what looks like this:
Count=1, ScannedCount=1, Items=[{'id': Decimal('7564')}], LastEvaluatedKey={'id': Decimal('7564'), 'pkey': 'customer1'}
Count=1, ScannedCount=1, Items=[{'id': Decimal('7565')}], LastEvaluatedKey={'id': Decimal('7565'), 'pkey': 'customer1'}
Count=0, ScannedCount=1, Items=[], LastEvaluatedKey={'id': Decimal('7566'), 'pkey': 'customer1'}
Count=1, ScannedCount=1, Items=[{'id': Decimal('7566')}], LastEvaluatedKey={'id': Decimal('7566'), 'pkey': 'customer1'}
Count=1, ScannedCount=1, Items=[{'id': Decimal('7567')}], LastEvaluatedKey={'id': Decimal('7567'), 'pkey': 'customer1'}
How is this possible?
First of all, Count and ScannedCount should be the same. From the documentation:
Count (integer) --
The number of items in the response.
If you used a QueryFilter in the request, then Count is the number of items returned after the filter was applied, and ScannedCount is the number of matching items before the filter was applied.
If you did not use a filter in the request, then Count and ScannedCount are the same.
QueryFilter is deprecated; should read FilterExpression. Neither of which I use in my query.
Second, the LastEvalulatedKey shows me the key that I want, but this is inclusive. Meaning that it has already been scanned, but determined that it was not a match.
Any ideas?