この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
DynamoDBテーブルでscan()
やquery()
を使うとき、フィルタを使うことがあります。
そこでふと気になりました。フィルタ適応後のデータが0件でも、続きはあるよね?と。
最初にまとめ
DynamoDBでscan()やquery()を使うとき、「続きのデータがある?(最後のデータ?)」の判断は、LastEvaluatedKey
を参照しましょう。データ件数で判断しないように注意です。
DynamoDBテーブルを準備する
以前に作成したDynamoDBテーブルを流用します。
scan()で調べてみる
1回のscan()
で最大1MBのデータを取得できますが、実際に用意するのは大変なので、Limit
を使って取得するデータ量を減らします。
まずは、Limit無しで試してみる
Limit
無しでtitleに「買う」が含まれているデータ取得できるか試してみます。
get_no_limit.py
import boto3
from boto3.dynamodb.conditions import Attr
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
options = {
'FilterExpression': Attr('title').contains('買う'),
}
res = table.scan(**options)
if len(res.get('Items', [])) == 0:
print('data is nothing.')
else:
print('data is exist.')
data = res.get('Items', [])
dump(data)
if 'LastEvaluatedKey' not in res:
print('LastEvaluatedKey is nothing.')
else:
print('LastEvaluatedKey is exist.')
print(res['LastEvaluatedKey'])
def dump(items):
for item in items:
print(item)
if __name__ == '__main__':
main()
タイトルに買う
が含まれているデータを取得できました。また、1回のscan()
で全データを取得できています(続きは無い)。
$ python get_no_limit.py
data is exist.
{'todoId': 't0001', 'tags': {'Amazon', '買い物', '単三'}, 'userId': 'u0001', 'title': '電池を買う'}
{'todoId': 't0003', 'userId': 'u0001', 'tags': {'買い物', 'スーパー'}, 'title': 'ちくわを買う'}
LastEvaluatedKey is nothing.
Limitをつけて、取得したデータが0件でも、続きがあるか試してみる
Limit
を指定して、続きのデータがあるか試してみます。
get_no_limit.py
import boto3
from boto3.dynamodb.conditions import Attr
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
options = {
'FilterExpression': Attr('title').contains('買う'),
'Limit': 1,
}
res = table.scan(**options)
if len(res.get('Items', [])) == 0:
print('data is nothing.')
else:
print('data is exist.')
data = res.get('Items', [])
dump(data)
if 'LastEvaluatedKey' not in res:
print('LastEvaluatedKey is nothing.')
else:
print('LastEvaluatedKey is exist.')
print(res['LastEvaluatedKey'])
def dump(items):
for item in items:
print(item)
if __name__ == '__main__':
main()
取得したデータは0件でしたが、LastEvaluatedKey
があるので、続きのデータが存在することがわかります。
$ python get_no_limit.py
data is nothing.
LastEvaluatedKey is exist.
{'todoId': 't0005', 'userId': 'u1111'}
おまけ:Limitありで全データを取得する
最後のデータでない場合は、LastEvaluatedKey
が渡されるので、ループすると全データを取得できます。
get_limit_all_data.py
import boto3
from boto3.dynamodb.conditions import Attr
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
options = {
'FilterExpression': Attr('title').contains('買う'),
'Limit': 1,
}
data = []
while True:
res = table.scan(**options)
data += res.get('Items', [])
if len(res.get('Items', [])) == 0:
print('data is nothing.')
else:
print('data is exist.')
data = res.get('Items', [])
dump(data)
if 'LastEvaluatedKey' not in res:
print('LastEvaluatedKey is nothing.')
else:
print('LastEvaluatedKey is exist.')
print(res['LastEvaluatedKey'])
# 続きのデータが無ければ、取得ループを抜ける
if 'LastEvaluatedKey' not in res:
break
options['ExclusiveStartKey'] = res['LastEvaluatedKey']
def dump(items):
for item in items:
print(item)
if __name__ == '__main__':
main()
ループをすることで、全データの取得ができました。
$ python get_limit_all_data.py
data is nothing.
LastEvaluatedKey is exist.
{'todoId': 't0005', 'userId': 'u1111'}
data is nothing.
LastEvaluatedKey is exist.
{'todoId': 't0006', 'userId': 'u1111'}
data is exist.
{'todoId': 't0001', 'tags': {'Amazon', '単三', '買い物'}, 'userId': 'u0001', 'title': '電池を買う'}
LastEvaluatedKey is exist.
{'todoId': 't0001', 'userId': 'u0001'}
data is nothing.
LastEvaluatedKey is exist.
{'todoId': 't0002', 'userId': 'u0001'}
data is exist.
{'todoId': 't0003', 'userId': 'u0001', 'tags': {'スーパー', '買い物'}, 'title': 'ちくわを買う'}
LastEvaluatedKey is exist.
{'todoId': 't0003', 'userId': 'u0001'}
data is nothing.
LastEvaluatedKey is exist.
{'todoId': 't0004', 'userId': 'u0001'}
data is nothing.
LastEvaluatedKey is nothing.