おまじないの綴り方

spelling of a logical spell

boto3 + DynamoDBでリストに要素を追加・削除

目標

dynamoDBに入っているリスト要素に対して、追加・削除を行う

環境

コード

import boto3
import decimal
import json
from boto3.dynamodb.conditions import Key, Attr

# DB設定
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('table')

# Helper class to convert a DynamoDB item to JSON.
# AWSのドキュメントにあったもの。これがないとnumber <-> floatの変換周りでエラーになる
class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        return super(DecimalEncoder, self).default(o)

# 本体
def lambda_handler(event, context):

    ##### 要素の削除

    # リストのうち削除したい要素番号を定義しておく
    index = 0

    res = table.update_item(
        Key={
            # アップデートするレコードの条件
            # 例: idカラム(プライマリキー)=1のとき
            'id': 1,
        },
        # Remove命令でリストから要素を削除する。
        # 基本形: REMOVE カラム名[要素番号]
        # ExpressionAttributeValuesでの要素番号指定は(何故か)できないので、削除する要素番号が可変の場合は無理やり渡している
        UpdateExpression="REMOVE #attribute[" + str(index) + "]",
        ExpressionAttributeNames= {
            # UpadateExpressionで使っている#attributeを置き換える
            # リスト要素の名前、今回はtarget_listだと仮定する
            '#attribute': "target_list"
        },
        # DB操作に直接影響しないので好みに合わせて
        ReturnValues="UPDATED_NEW"
    )

    ##### 要素の追加

    # 追加する要素には、数値・文字列・バイナリが指定可能
    # boto経由だと、変数の型が考慮されるようなので注意(そのかわりN,S,Bの指定はいらない?)
    append_value = 0

    res = table.update_item(
        Key={
            # 例: idカラム(プライマリキー)=1のとき
            'id': 1,
        },
        # list_appendでlist同士をつなぎ、SET命令で新しいリストを代入する
        # 基本形: SET カラム名 = list_append(リスト1, リスト2)
        # list同士の結合命令なので、追加要素が一つしかなくてもリストの形で渡す
        # ExpressionAttributeValuesが使えるのでこちらを使ったほうがよさそう
        UpdateExpression="SET #attribute = list_append(#attribute, :val)",
        ExpressionAttributeNames= {
            # UpadateExpressionで使っている#attributeを置き換える
            # リスト要素の名前、今回はtarget_listだと仮定する
            '#attribute': "target_list"
        },
        ExpressionAttributeValues={
            # UpadateExpressionで使っている:valを実際の値で置き換える
            ':val': [append_value]
        },
        # DB操作に直接影響しないので好みに合わせて
        ReturnValues="UPDATED_NEW"
    )

備考

Number Setに対して同じことをやろうとするときはADD命令を使うらしいが、うまく行かなかった。 botoで実現可能なのだろうか。。。