[[AWSメモ]] > * DynamoDBでドキュメント型項目を部分的に更新する [#b93e02a5] #setlinebreak(on) #contents -- 参考 --- https://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Table.update_item --- https://boto3.readthedocs.io/en/latest/reference/customizations/dynamodb.html#boto3.dynamodb.conditions.Attr --- https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements -- 関連 --- [[DynamoDBでドキュメント型の更新]] ** 概要 [#g30dbc9a] #html(<div style="padding-left:10px;">) 例えば、以下のような内容のデータがある時、map1配下の field1 の内容だけを更新する方法について記載する。 テーブル名: TestMap、パーティションキー: id #mycode2(){{ { "id": "001", "map1": { "field1": { "value": "a1", "timestamp": "2018-07-01T00:00:00Z" }, "field2": { "value": "a2", "timestamp": "2018-07-01T00:00:00Z" } } } }} #html(</div>) ** マップの配下の項目を部分的に更新する[#k9ddf6b2] #html(<div style="padding-left:10px;">) 普通に、UpdateExpression に 配下の項目を . (ドット)で区切って指定するだけで良い。 ただし、timestamp や input など、DynamoDBの 予約語を含む場合は、ExpressionAttributeNames を使用して別名を指定する必要がある。 #mycode2(){{ import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('TestMap') operation_args = { 'Key': {'id': '001'}, 'UpdateExpression': 'set map1.field1 = :map1_field1', 'ExpressionAttributeValues': {':map1_field1': {'value':'aa1', 'timestamp': '2018-07-23T00:00:00Z'}}, 'ReturnValues': 'UPDATED_NEW', } result = table.update_item(**operation_args) if __name__ == '__main__': main() }} #html(</div>) ** マップ配下の項目を更新条件に指定する [#k9ddf6b2] #html(<div style="padding-left:10px;">) boto3.dynamodb.conditions.Attr などを使用して 普通に ConditionExpression を指定すればOK。 以下は、map1.field1 の更新前のtimestampが指定日時より前の場合だけ更新する。 ※条件を満たさない場合は、botocore.errorfactory.ConditionalCheckFailedException が発生する。 #mycode2(){{ import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('TestMap') operation_args = { 'Key': {'id': '001'}, 'UpdateExpression': 'set map1.field1 = :map1_field1', 'ExpressionAttributeValues': {':map1_field1': {'value':'aa1', 'timestamp': '2018-07-23T00:00:00Z'}}, 'ReturnValues': 'UPDATED_NEW', 'ConditionExpression': Attr('map1.field1.timestamp').lt('2018-07-23T00:00:00Z') } result = table.update_item(**operation_args) if __name__ == '__main__': main() }} #html(</div>) ** リストに要素を追加する [#tf5391b7] #html(<div style="padding-left:10px;">) リストに要素を追加する場合は、SET で list_append関数を使用する。 リストに要素を追加する場合は、SET句 で list_append関数を使用する。 https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements #html(<table style="margin-bottom:10px;"><tr><td style="vertical-align:top;">) 更新前 #mycode2(){{ { "id": "002", "list1": [ {"key": "sub1", "val": 1} ] } }} #html(</td><td style="vertical-align:top;padding-left:20px;">) 更新後 #mycode2(){{ { "id": "002", "list1": [ {"key": "sub1", "val": 1}, {"key": "sub2", "val": 2} // 追加 ] } }} #html(</td></tr></table>) #mycode2(){{ import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('TestMap') operation_args = { 'Key': {'id': '002'}, 'UpdateExpression': 'SET list1 = list_append(list1, :list1_add_data)', 'ExpressionAttributeValues': {':list1_add_data': [{'key':'sub2', 'val': 2}]}, 'ReturnValues': 'UPDATED_NEW', } result = table.update_item(**operation_args) def list_append(field_name, field_value): pass if __name__ == '__main__': main() }} #html(</div>) ** Map要素の配下のリストに要素を追加する [#r0846af3] #html(<div style="padding-left:10px;">) Map配下にあるリストに要素を追加する場合も list_append で更新可能。 #html(<table style="margin-bottom:10px;"><tr><td style="vertical-align:top;">) 更新前 #mycode2(){{ { "id": "004", "map1": { "sublist1" :[ {"key": "sub1", "val": 1} ] ] } }} #html(</td><td style="vertical-align:top;padding-left:20px;">) 更新後 #mycode2(){{ { "id": "004", "map1": { "sublist1" :[ {"key": "sub1", "val": 1}, {"key": "sub2", "val": 2} // 追加 ] ] } }} #html(</td></tr></table>) #mycode2(){{ import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('TestMap') operation_args = { 'Key': {'id': '003'}, 'UpdateExpression': 'SET map1.sublist1 = list_append(map1.sublist1, :list1_add_data)', 'ExpressionAttributeValues': {':list1_add_data': [{'key':'sub2', 'val': 2}]}, 'ReturnValues': 'UPDATED_NEW', } result = table.update_item(**operation_args) def list_append(field_name, field_value): pass if __name__ == '__main__': main() }} #html(</div>) ** リスト配下のリストに要素を追加する [#r489d2db] #html(<div style="padding-left:10px;">) 以下のように、リスト配下のN番目の要素(Map)の配下にあるリストを更新する場合なども 同じ様に list_append で更新できる。 #html(<table style="margin-bottom:10px;"><tr><td style="vertical-align:top;">) 更新前 #mycode2(){{ { "id": "004", "list1": [ { "sublist": [ {"key": "sub1", "val": 1} ] } ] } }} #html(</td><td style="vertical-align:top;padding-left:20px;">) 更新後 #mycode2(){{ { "id": "003", "list1": [ { "sublist": [ {"key": "sub1", "val": 1}, {"key": "sub2", "val": 2} // 追加 ] } ] } }} #html(</td></tr></table>) #mycode2(){{ import boto3 from boto3.dynamodb.conditions import Attr def main(): dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('TestMap') operation_args = { 'Key': {'id': '003'}, 'UpdateExpression': 'SET list1[0].sublist = list_append(list1[0].sublist, :list1_add_data)', 'ExpressionAttributeValues': {':list1_add_data': [{'key':'data2', 'val': 2}]}, 'ReturnValues': 'UPDATED_NEW', } result = table.update_item(**operation_args) def list_append(field_name, field_value): pass if __name__ == '__main__': main() }} #html(</div>)