この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
IoT機器を管理する方法のひとつとして、タグを検討しています。たとえば下記です。
- 機器1: 工場A、1階、担当X
- 機器2: 工場A、1階、担当Z
- 機器3: 工場B、2階、担当Z、机の上
ユーザが任意にタグを付けて、自由に管理できるイメージです。
これらの管理をDynamoDBテーブルで実現する方法として、DynamoDBのSet型を試してみました。
おすすめの方
- DynamoDBでSet型を使いたい方
ToDoテーブルのサンプル
userId | todoId | title | tags |
---|---|---|---|
u0001 | t0001 | 電池を買う | 買い物, Amazon, スーパー |
u0001 | t0002 | 映画を見る | 映画, Amazon |
u0001 | t0003 | ちくわを買う | 買い物, スーパー |
u0001 | t0004 | AWS認定試験を申し込む | 勉強, AWS, 趣味 |
u1111 | t0005 | 熊の置物を掘る | 趣味, プレゼント |
u1111 | t0006 | ラーメンを食べる | 趣味, ご飯 |
DynamoDBテーブルをデプロイする
CloudFormationテンプレート
dynamodb.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Todo DynamoDB Sample
Resources:
TodoTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: todo-tag-sample-table
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
- AttributeName: todoId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: todoId
KeyType: RANGE
デプロイ
aws cloudformation deploy \
--template-file dynamodb.yaml \
--stack-name Todo-Tag-DynamoDB-Sample-stack
DynamoDBテーブルを操作する
データ追加
下記でデータを追加します。tags
部分はset型です。
insert.py
import boto3
INSERT_ITEMS = [
{
'userId': 'u0001',
'todoId': 't0001',
'title': '電池を買う',
'tags': {'買い物', 'Amazon', 'スーパー'}
},
{
'userId': 'u0001',
'todoId': 't0002',
'title': '映画を見る',
'tags': {'映画', 'Amazon'}
},
{
'userId': 'u0001',
'todoId': 't0003',
'title': 'ちくわを買う',
'tags': {'買い物', 'スーパー'}
},
{
'userId': 'u0001',
'todoId': 't0004',
'title': 'AWS認定試験を申し込む',
'tags': {'勉強', 'AWS', '趣味'}
},
{
'userId': 'u1111',
'todoId': 't0005',
'title': '熊の置物を掘る',
'tags': {'趣味', 'プレゼント'}
},
{
'userId': 'u1111',
'todoId': 't0006',
'title': 'ラーメンを食べる',
'tags': {'趣味', 'ご飯'}
},
]
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
insert_items(table)
def insert_items(table):
for item in INSERT_ITEMS:
table.put_item(Item=item)
if __name__ == '__main__':
main()
DynamoDBテーブルの様子です。tags
はStringSet
になっています。DynamoDBのドキュメントではSS
と表記される場合もあります。
データ検索
特定ユーザで、全データを取得する
userId
を指定してquery()
を実行します。
query_user_all.py
import boto3
from boto3.dynamodb.conditions import Key
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
ret = get_all(table, 'u0001')
dump(ret)
def get_all(table, user_id):
options = {
'KeyConditionExpression': Key('userId').eq(user_id),
}
data = []
while True:
res = table.query(**options)
data += res.get('Items', [])
if 'LastEvaluatedKey' not in res:
break
options['ExclusiveStartKey'] = res['LastEvaluatedKey']
return data
def dump(items):
for item in items:
print(item)
if __name__ == '__main__':
main()
$ python query_user_all.py
{'todoId': 't0001', 'userId': 'u0001', 'tags': {'Amazon', '買い物', 'スーパー'}, 'title': '電池を買う'}
{'todoId': 't0002', 'userId': 'u0001', 'tags': {'Amazon', '映画'}, 'title': '映画を見る'}
{'todoId': 't0003', 'userId': 'u0001', 'tags': {'買い物', 'スーパー'}, 'title': 'ちくわを買う'}
{'todoId': 't0004', 'userId': 'u0001', 'tags': {'趣味', '勉強', 'AWS'}, 'title': 'AWS認定試験を申し込む'}
特定ユーザで、特定タグを含むデータを取得する
userId
とtags
を指定してquery()
を実行します。
query_user_tags.py
import boto3
from boto3.dynamodb.conditions import Attr, Key
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
ret = get_include_tag(table, 'u0001', 'スーパー')
dump(ret)
def get_include_tag(table, user_id, tag):
options = {
'KeyConditionExpression': Key('userId').eq(user_id),
'FilterExpression': Attr('tags').contains(tag),
}
data = []
while True:
res = table.query(**options)
data += res.get('Items', [])
if 'LastEvaluatedKey' not in res:
break
options['ExclusiveStartKey'] = res['LastEvaluatedKey']
return data
def dump(items):
for item in items:
print(item)
if __name__ == '__main__':
main()
$ python query_user_tags.py
{'todoId': 't0001', 'userId': 'u0001', 'tags': {'買い物', 'スーパー', 'Amazon'}, 'title': '電池を買う'}
{'todoId': 't0003', 'userId': 'u0001', 'tags': {'スーパー', '買い物'}, 'title': 'ちくわを買う'}
また、下記のように複数条件を指定可能です。
options = {
'KeyConditionExpression': Key('userId').eq(user_id),
'FilterExpression': Attr('tags').contains('買い物') & Attr('tags').contains('Amazon'),
}
options = {
'KeyConditionExpression': Key('userId').eq(user_id),
'FilterExpression': Attr('tags').contains('買い物') | Attr('tags').contains('Amazon'),
}
データ更新
タグを追加する
add
の更新式でタグを追加します。
update_add_tags.py
import boto3
from boto3.dynamodb.conditions import Attr
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
update(table, 'u0001', 't0001', '単三')
def update(table, user_id, todo_id, tag):
options = {
'Key': {
'userId': user_id,
'todoId': todo_id,
},
'UpdateExpression': 'add #tags :tag',
'ExpressionAttributeNames': {
'#tags': 'tags',
},
'ExpressionAttributeValues': {
':tag': {tag}
},
}
table.update_item(**options)
if __name__ == '__main__':
main()
「単三」が追加されました。
タグを削除する
delete
の更新式でタグを削除します。
update_remove_tags.py
import boto3
from boto3.dynamodb.conditions import Attr
def main():
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('todo-tag-sample-table')
update(table, 'u0001', 't0001', 'スーパー')
def update(table, user_id, todo_id, tag):
options = {
'Key': {
'userId': user_id,
'todoId': todo_id,
},
'UpdateExpression': 'delete #tags :tag',
'ExpressionAttributeNames': {
'#tags': 'tags',
},
'ExpressionAttributeValues': {
':tag': {tag}
},
}
table.update_item(**options)
if __name__ == '__main__':
main()
「スーパー」が削除されました。
さいごに
DynamoDBのSet型を試してみました。いい感じに使えそうです。