Amazon Web Services ブログ

Amazon DynamoDB での JSON データの扱い

Amazon DynamoDBは JSON オブジェクトを属性として保存することができ、フィルタリング、更新、削除など様々なオペレーションに使用することができます。この機能はアプリケーションがオブジェクトタイプのデータ( JSON , 配列など )を直接 DynamoDB のテーブルに保存、データベースのオペレーションでネストされている属性を使用可能な強力な機能です。本記事では DynamoDB で JSON データオブジェクトで実現可能ないくつかの機能を紹介します。

DynamoDB shell ( ddbsh ) のインストール

DynamoDB shell ( ddbsh ) は Mac では homebrew, Ubuntu では フリービルトされたバイナリパッケージを github から入手できます。詳細はフリービルトされたバイナリパッケージを使用を参考してください。

ソリューションの概要

本記事では DynamoDB shell ( ddbsh ) の機能を説明します。より詳細な情報は DynamoDB Shell クエリデータ – DynamoDB のコマンドラインインタフェースをご覧ください。ddbsh の目標の1つは DynamoDB を初めて使用するユーザが慣れている SQL と類似なコマンドを実行してスタート可能な簡単明瞭な環境を提供することです。

ddbsh 中のクエリ言語は SQL で派生されたもので DynamoDB 関連拡張機能があります。

本記事ではファストフードの注文をトラックキンする簡単なテーブルを使用します。サンプルのオーダコードは以下となります。

{ ono: 12, ino: 1, details: { entree: “burger”, sides: [ “fries”, “soda” ]}, status: “WIP” }

完了された注文は以下のように見えます。

{ ono: 15, ino: 1, details: { entree: “salad”, sides: [ “apple”, “water” ]}, status: “DONE” }

3つのアイテムを持っている注文は以下となります。

{ ono: 14, ino: 1, details: { entree: “salad”, sides: [ “apple”, “water” ]}, status: “WIP” }
{ ono: 14, ino: 2, details: { entree: “BLT sw”, sides: [ “water” ]}, status: “WIP” }

下記のセクションではテーブルの作成及びサンプルデータの導入、データのクエリ、アイテムの更新、属性の追加、削除を行う方法を確認します。また、 SQL をアプリケーションで一連のAPIコールに変換する方法も説明します。

前提条件

事前に DynamoDB shell をインストールする必要があります。詳しくはDynamoDB Shell クエリデータ – DynamoDB のコマンドラインインタフェースをご覧ください。

データの準備

DynamoDB テーブルを以下のコードで作成します。
( バージニア北部 us-east-1 リージョンを使用します。)

us-east-1> CREATE TABLE ORDERS ( ono number, ino number ) PRIMARY KEY (ono hash, ino range);
CREATE
us-east-1>

次は、下記のコードで DynamoDB のテーブルに4つの行を追加します。

us-east-1> insert into ORDERS (ono, ino, details, status) 
values (12, 1, {entree: "burger", sides: ["fries", "soda"]}, "WIP"), 
(14, 1, {entree: "salad", sides: ["apple", "water"]}, "WIP"), 
(14, 2, {entree: "BLT sw", sides: ["water"]}, "WIP"), 
(15, 1, {entree: "salad", sides: ["apple", "water"]}, "DONE"); 
INSERT 
INSERT 
INSERT 
INSERT 
us-east-1> select * from ORDERS; 
{details: {entree:salad, sides:[apple, water]}, ino: 1, ono: 14, status: WIP} 
{details: {entree:"BLT sw", sides:[water]}, ino: 2, ono: 14, status: WIP} 
{details: {entree:burger, sides:[fries, soda]}, ino: 1, ono: 12, status: WIP} 
{details: {entree:salad, sides:[apple, water]}, ino: 1, ono: 15, status: DONE} 
us-east-1>

これでデータをクエリする準備が終わりました。

データのクエリ

はじめに、以下のクエリを実行することでオーダ番号14( ono 14 ) のアイテムを確認できます

us-east-1> select * from ORDERS where ono = 14 and ino = 1;
{details: {entree:salad, sides:[apple, water]}, ino: 1, ono: 14, status: WIP}
us-east-1>

また、別のクエリでサイドに水( side : water )を指定しれいる完了されてない注文( status : wip ) を確認することも可能です。

us-east-1> select * from ORDERS where status != "DONE" and contains(details.sides, "water");
{details: {entree:salad, sides:[apple, water]}, ino: 1, ono: 14, status: WIP}
{details: {entree:"BLT sw", sides:[water]}, ino: 2, ono: 14, status: WIP}
us-east-1>

ここでは DynamoDB が JSON オブジェクト( detail )を分解、属性である sides を探し、その配列の中にに水( water )が含まれいるかを確認しました。
下記のクエリでポテト( fries ) が準備されて、処理されるべきの注文を確認できます。

us-east-1> select ono, ino from ORDERS where contains(details.sides, "fries") and status = "WIP";
{ino: 1, ono: 12}
us-east-1>

類似にバーガー( burger )が準備されて、処理を待つ注文を確認できます。

us-east-1> select ono, ino from ORDERS where details.entree = "burger" and status = "WIP";
{ino: 1, ono: 12}
us-east-1>

アイテムの更新

DynamoDB shell でこれらのアイテムを更新することができます。例えば注文番号14番の1つのアイテムを注文した顧客が水( water )の代わりに炭酸( soda )を希望する場合を想定します。

us-east-1> select * from ORDERS where ono = 14 and ino = 1;
{details: {entree:salad, sides:[apple, water]}, ino: 1, ono: 14, status: WIP}
us-east-1>

us-east-1> update ORDERS set details.sides[1] = "soda" where ono = 14 and ino = 1;
UPDATE (0 read, 1 modified, 0 ccf)
us-east-1>

us-east-1> select * from ORDERS where ono = 14 and ino = 1;
{details: {entree:salad, sides:[apple, soda]}, ino: 1, ono: 14, status: WIP}
us-east-1>

アップデートがインデックス別に details.sides 配列の項目を参照するか確認します。2番目の項目( インテックス1 )がここで更新されます。

取り込まれたオブジェクトに属性を追加、削除

顧客が特殊な要望を持っている場合、注文にそれを反映することができます。

us-east-1> update ORDERS set details.notes = "extra dressing" where ono = 14 and ino = 1;
UPDATE (0 read, 1 modified, 0 ccf)
us-east-1> select * from ORDERS where ono = 14;
{details: {entree:salad, notes:"extra dressing", sides:[apple, water]}, ino: 1, ono: 14, status: WIP}
{details: {entree:"BLT sw", sides:[water]}, ino: 2, ono: 14, status: WIP}
us-east-1>

BLT サンドウィッチを注文した顧客が水が不要と決めた場合、以下のコードを使用します。

us-east-1> update ORDERS remove details.sides where ono = 14 and ino = 2;
UPDATE (0 read, 1 modified, 0 ccf)
us-east-1> select * from ORDERS where ono = 14 and ino = 2;
{details: {entree:"BLT sw"}, ino: 2, ono: 14, status: WIP}
us-east-1>

SQL を DynamoDB API に変更

DynamoDB でアプリケーションを作成する際に SQL を使用して処理する作業のプロトタイプを素早く作ることはメリットがありますが、その後にアプリケーションの API コールセットに変更する場合があります。 ddhshの EXPLAIN コマンドを使用すると、上記の UPADTE 文を変更するのに役に立ちます。

us-east-1> explain update ORDERS set details.sides[1] = "soda" where ono = 14 and ino = 1;
UpdateItem({
"TableName": "ORDERS",
"Key": {
"ino": {
"N": "1"
},
"ono": {
"N": "14"
}
},
"UpdateExpression": "SET #aTaa1.#aTaa2[1] = :vTaa1",
"ConditionExpression": "attribute_exists(#aTaa3)",
"ExpressionAttributeNames": {
"#aTaa1": "details",
"#aTaa2": "sides",
"#aTaa3": "ono"
},
"ExpressionAttributeValues": {
":vTaa1": {
"S": "soda"
}
}
})
us-east-1>

EXPLAIN はクエリ( 全体のプライマリキー、onoino ) が UpdateItem() に変換可能なことを見せます。て0ブルの名前、キーが指定されます。 アップデートの表現式は以下のようにインコーディングされます。

"UpdateExpression": "SET #aTaa1.#aTaa2[1] = :vTaa1"

これはスキマに存在可能なすべての予約語を処理するため実行されます。プレースホルダーを属性名に変更すると安全にアップデートを実行できます。 ddbshdetails#aTaa1 , sides#aTaa2 に変換しました。値( soda )は :vTaa1 に変換されました。 DynamoDB の UpdateItem() は項目がない場合、項目をインサートするため、 ddbsh はチェックを行います。#aTaa3 は属性 one に対するプレースホルダーです。

"ConditionExpression": "attribute_exists(#aTaa3)"

キー条件がプライマリキーを提供したため、プライマリキーと一致する項目がある場合、属性 ono がアイテムに存在するようになります。

以下のコードは API コールに変換する別の例です。

use-east-1> explain update ORDERS remove details.sides where ono = 14 and ino = 2;
UpdateItem({
"TableName": "ORDERS",
"Key": {
"ino": {
"N": "2"
},
"ono": {
"N": "14"
}
},
"UpdateExpression": "REMOVE #aeba1.#aeba2",
"ConditionExpression": "attribute_exists(#aeba3)",
"ExpressionAttributeNames": {
"#aeba1": "details",
"#aeba2": "sides",
"#aeba3": "ono"
}
})
us-east-1>

クリーンアップ

テストが完了されたらコストを避けるためすべてのテーブルを削除する必要があります。そのためには ddbsh から DROP TABLE を使用可能です。

us-east-1> drop table ORDERS;
DROP
us-east-1>

まとめ

DynamoDB を使用すると JSON データを属性に保存できます。その後、データをクエリ、 JSON オブジェクトの内部のデータを扱うことが可能です。
我々は DynamoDB API を学ぶためのリソースを希望するお客様及び暫定的なカスタマの声を確認しました。本記事で紹介した ddbsh の EXPLAIN コマンドなどいくつかのソリューションを試しています。 このツールに関するあなたのフィードバックに感謝します。 DynamoDB より楽に使えるため ddbsh に追加する機能の意見を集めています。
最後に、 ddbsh に実装を希望する特定機能があればサポートチケットを記載するか amrithie (at) amazon.com. に直接メールをお願いいたします。

(本記事は 2023/05/01に投稿された Working with JSON data in Amazon DynamoDB を翻訳した記事です。)

作者

Amrith Kumar は Amazon Web Service シニアプリンシパルエンジニアで Amazon DynamoDB の仕事をしています.