- 真野隼記
- 約 2,800 文字
- 2,300 View
目次
by Renée French
はじめに
TIG真野です。
DynamoDBをGoで操作することにかけては、DynamoDB×Go連載 に参加するくらい関心があるのですが、AWS SDK for Goの公式ライブラリに含まれる、ヘルパーパッケージについて存在を今までスルーしていました。使ってみると業務的には利用一択だと思ったので今後使っていくぞという覚書としてまとめます。
DynamoDBの式をダイレクトに実装した例
私は公式のAWS SDK for Goのdynamodbパッケージを用いる時に、ドキュメントのExampleに書いてあるように、ちまちま ExpressionAttributeNamesやExpressionAttributeValuesやFilterExpressionやProjectionExpressionを指定していました。
どんな感じかと言うと次のような感じです。
func ScanMusic() { |
これはこれで、DynamoDBのREST APIの仕様に詳しくなれるのと、AWS CLIを用いたDynamoDBアクセスする時と知識を流用できるので学びにはなるのですが、利用項目や条件が増えてくるとレビュー観点でツライですし、自分が実装するときもExpressionAttributeNames が抜けていてエラーになるなど、生産性という意味では開発者側が試されているなと感じることが多かったです。
ヘルパーパッケージの福音
業務でも様々な技術ブログでも DynamoDB SDK for Goを実装するときは上記のような設定をするコードをよく見ますが、実は公式に便利なヘルパーが用意されています。 expression パッケージです。式の組み立て全般をサポートしてくれるビルダーを提供してくれます。
expressionパッケージ を用いると、ExpressionAttributeNames や ExpressionAttributeValues や FilterExpression などのDynamoDBの式を型安全に構築できます。例をあげます。
func ScanMusic() { |
expression パッケージを利用して、フィルター条件やプロジェクション式を構築しています。ややコードとしては長くなりましたが、dynamodb.ScanInput のフィールドがの設定が一律シンプル下したことがわかります。この勢いで TableName も expr から指定したい気もしますが、それはパッケージの担当外なようです。
サンプルコードだけ見ると、心理的なハードルが高く思えるかもしれませんが、そもそも元の実装にあるような、ExpressionAttributeNames や ExpressionAttributeValues や FilterExpression の記載方法を覚え、正しく使用することの方が大変です。 expression パッケージを用いると、何かしら指定が論理的に正しくない場合は、式のビルド時にエラーで検知できるため、開発時のトラブルシュートにも役立つと思います。
AWS SDK for Goを生で用いてDynamoDBアクセスを行うのであれば、基本的には積極的に使っていくパッケージでしょう。
論理式
先程の例ではEqualでしたが、ドキュメントを見る通り、AND, OR, NotEqualや、LessThan, GreaterThan などなど、一通りの演算子が揃っています。選び放題・使い放題のガッツがあるパッケージです。
https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/expression/
例えばフィルターで、Artistが Red, Green, Blue のどれかという条件を指定すると以下のようになります。
filt := expression.Name("Artist").Equal(expression.Value("Red")). |
もちろんAND, ORもネスト化できます。Artist が Blue のときは Year が 2021 年であると追加します。
filt := expression.Name("Artist").Equal(expression.Value("Red")). |
式で表現すると Artist == Red || Artist == Green || (Artist == Blue && Year == 2021) といった感じでしょうか。式が複雑になる場合はこういった擬似コードでコメントの補足を入れると良いかなと思います。
ProjectionExpressionを指定するのが面倒問題
expressionパッケージを利用していくと、Projectionの設定が面倒な場合があります。
filt := expression.Name("Artist").Equal(expression.Value("No One You Know")) |
この場合は自前で一工夫すると良いでしょう。ヘルパー関数をさらに作っても良いかもしれません。
filt := expression.Name("Artist").Equal(expression.Value("No One You Know")) |
このあたりを作り込みすぎると、独自DSLを作るような感じになるかと思いますが、愚直に書きすぎると表現の密度が下がりすぎて保守がツライ場合もあるので、バランスを見て取り入れて行くと良いかなと思います。
クエリの場合
先程まではScanの例でしたが、Queryの場合はさらに expression が役立ちます。ハッシュキーに DeviceID、ソートキーに Timestamp という典型的な時系列データを保持するDeviceLogというテーブルに対しての実装例です。
var db = dynamodb.New(session.Must(session.NewSession())) |
あるデバイスに対して、開始~終了日時を指定し、さらに適当なフィルター条件も追加しました。クエリの場合は、KeyConditionExpressionと FilterExpression の両方が設定できるため、expression パッケージを利用しない時はExpressionAttributeNames と ExpressionAttributeValues の管理が煩雑になりがちでした。
Update Expression
DynamoDBに対するUpdate式も、クエリと同様になかなかとっつき難かったです。expressionパッケージを用いない場合は、通常の文字列なのでカンマの位置などかなり気をつけることが多いです。
var db = dynamodb.New(session.Must(session.NewSession())) |
これは expression パッケージを用いると次のようになります。
var db = dynamodb.New(session.Must(session.NewSession())) |
式の構築部分が型セーフに実装できていることが分かると思います。
少し残念なのは、 Key の部分は expr から生成できないということでしょうか。ここだけはハッシュキー(とソートキー)をダイレクトに指定する必要があるので、レベル感がズレて勿体ない気がします(KeyConditionのように指定したかったですね)
まとめ
AWS SDK for Goの dynamodb パッケージを用いると時に必須とも言える、 expression パッケージの使い方について触れました。
expression パッケージを用いると、従来DynamoDBのAPI仕様を理解したフィールドや、文字列で式を設定する必要があった部分を、型安全に構築できます。
いくつか残念なところはあるにしろ、メリットは計り知れないのでうまく活用していきたいですね。