boto3のresoureをclientに移行する為のDynamoDB Json, FilterExpression周りのTips

こんにちは、けんご(@N30nnnn)です。

2023/1にboto3のresourceインターフェースが更新されなくなるとの告知がなされ、例に漏れずclientインターフェースへの移行を進めています。

Resources - Boto3 Docs 1.26.89 documentation

AWS Python SDK(boto3)のリソース・インターフェースが改修凍結されました | DevelopersIO

その過程で dynamodbのresourceをclientに移行するの面倒くさいなと思ってたのですが、boto3に便利な変換機があったのでご紹介します。

dynamodb jsonへの変換

例えば、dynamodbの get_item() を例に取ると、Keyに渡す値違いがあります

  • resoure
    • {"partition_key_name": value}
  • client
    • {"partition_key_name": {"S": value}}

上記の様にclientは型情報を付与する必要があり、変換しなければいけません。

こちらの変換は、classmethodさんの記事になってました。

DynamoDB JSONの型変換をboto3だけで行ってみる | DevelopersIO

これは下記クラスを使うと手軽に型情報の付与•除去をすることが可能です。

  • boto3.dynamodb.types.TypeSerializer
  • boto3.dynamodb.types.TypeDeserializer
from boto3.dynamodb.types import TypeSerializer, TypeDeserializer

serializer = TypeSerializer()
deserializer = TypeDeserializer()

key = {"partition_key_name": "string-value"}

key = serializer.serialize(key)      # {"partition_key_name": {"S": "string-value"}}
key = deserializer.deserialize(key)  # {"partition_key_name": "string-value"}

これはdynamodbが対応してる型の入力は全部対応してくれ、map型などの深い構造も再帰的に行ってくれるので、とりあえずseralizer, deserializer に突っ込んで置けばよくて楽です。

FilterExpressionの変換

dynamodbのresourceインターフェースにおける scanquery などは、下記のようなFilterexpressionを指定すると取得されるデータを絞れます。

FilterExpression = (
    Attr('attr_name1').contains('xxxxxx') & 
    Attr('attr_name2').lt(100)
)

これはclientインターフェースに置いてはプレースホルダを用いて式•変数名•値を別々に渡す必要がありますが(詳細略)、 boto3.dynamodb.conditions.ConditionExpressionBuilder を用いると上記条件式を簡単にclientインターフェースに対応することが可能になります

from boto3.dynamodb.conditions import Attr, ConditionExpressionBuilder

builder = ConditionExpressionBuilder()

condition = (
    Attr('attr_name1').contains('xxxxxx') & 
    Attr('attr_name2').lt(100)
)

condition_expr, attr_name_placeholders, attr_value_placeholders = builder.build_expression(condition)
# condition_expr: '(contains(#n0, :v0) AND #n1 < :v1)'
# attr_name_placeholders: {'#n0': 'attr_name1', '#n1': 'attr_name2'}
# attr_value_placeholders: {':v0': 'xxxxxx', ':v1': 100}