銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

AWS LambdaからDynamoDBをQueryする

AWSAPIの具体的かつ網羅的な説明って、どこかにきちんとあるのでしょうか? ワタシは検索してもチュートリアルばかり出てきます。

DynamoDBのAPIは「Welcome Amazon DynamoDB」で説明されていますが、各言語から呼び出せるメソッドが記述されているわけではないので、定型的な読み替えと試行錯誤と推測が必要なんですね。

日本語に翻訳されている文書も有りますが、おおかた機械翻訳のようでして、かなり不可解なドキュメントに悩まされたり・・・。

f:id:takamints:20160223124534p:plain
photo credit: Violet electric lightning versus turquoise storm - 09072012 via photopin (license)

などと、文句ばかり言っていても始まらないので、ここはひとつ怒りに任せて(笑)Node.jsのLambda関数からDynamoDBを操作するサンプルコードを示してみます。コードや見識に間違いがあるかもしれませんから、妙なところを見つけられたらご指摘ください。いくつになってもお勉強です。

※ ここではAmazon DynamoDBAWS Lambdaについて、ひと通り基本的な知識を持っているって前提で書いてます。ワタシもAWS初心者なんですけどエラそうで申し訳ない。
※ フロントエンドは Amazon API Gatewayを利用している前提です。このため、実行結果はcontext.doneでJSON文字列を出力しています。


AWSCLIから、ちょっと便利に使えるコマンドセットをnpm aws-node-utilで公開しています。 以下の関連記事をご覧ください。

DynamoDB関連:

コマンドラインからプレースホルダーを気にせず、putItem / Query / Scan
takamints.hatenablog.jp

Lambda関連:

★ Lambda関数のアップロードとダウンロード
takamints.hatenablog.jp


AWSエキスパート養成読本[Amazon Web Servicesに最適化されたアーキテクチャを手に入れる! ] (Software Design plus)
吉田 真吾 今井 智明 大瀧 隆太 松井 基勝 冨永 善視 藤原 吉規 大栗 宗
技術評論社
売り上げランキング: 1,300

DynamoDB API Query - キー属性で項目を検索

DynamoDBのテーブルから検索条件に合致した項目を問い合わせるためには、Query を使用します。条件無しで全項目を得るには、Queryではなく Scan を使用します。

Queryの検索条件には、少なくともプライマリーキーの条件が指定されなくてはならず、これに加えて、プライマリーソートキーやセカンダリーインデックスの条件も AND / OR で連結して記述できます。

さらに、プライマリーキー以外の項目によるフィルター条件も指定できますが、これは、あくまでも上記のプライマリーキーによる検索結果を得た後に対して絞りこむものですから、クエリ自体のパフォーマンスには、ほぼ無関係でしょう。(レスポンスが少なくなるので、通信速度には影響すると思われます)

サンプルコード(Node.js)

以下のように少しややこしい。初めて見たら軽くめまいを覚えそうです。

var AWS = require('aws-sdk');
var dynamo = new AWS.DynamoDB({
    region: 'ap-northeast-1'
});
var tableName = "myTable";
exports.handler = function(event, context) {

    //パラメータ定義
    var params = {
        "TableName": tableName,
        //キー、インデックスによる検索の定義
        "KeyConditionExpression":
            "id = :Id AND #Ts BETWEEN :T0 AND :T1",
        //プライマリーキー以外の属性でのフィルタ
        "FilterExpression":
            "#Fn > :Fn",
        //属性名のプレースホルダの定義
        "ExpressionAttributeNames": {
            "#Ts": "timestamp",
            "#Fn": "value.floor"
        },
        //検索値のプレースホルダの定義
        "ExpressionAttributeValues": {
            ":Id" : { "S" : event.id },
            ":T0" : { "S" : event.T0 },
            ":T1" : { "S" : event.T1 }
            ":Fn" : { "S" : event.Fn }
        }
    };
    //クエリ実行
    dynamo.query(params, function(err, data) {
        if (err) {
            context.fail(
                new Error("Fail. err:" + err));
        } else {
            var response = JSON.stringify(data);
            context.done(null, response);
        }
    });
};

ポイントは、params。 ここではテーブルの指定以外に以下の3つのことをやっています。

  1. プライマリーキーによる検索を検索値のプレースホルダを使用して定義する
  2. プライマリーキー以外の属性で、キーの検索結果をフィルタする
  3. 属性名が予約語とかち合った場合は属性名のプレースホルダーで解決する

以降で、これらパラメータについて、もうちょっと詳細に説明します。

パラメータ

パラメータは第一引数に、objectとして与えられます。 下表に、ここで使用しているパラメータの概要です。

No. キー 説明
1 TableName string テーブル名を指定する。
2 KeyConditionExpression string キー属性での検索定義
3 ExpressionAttributeValues object 検索値のプレースホルダを定義する。
4 ExpressionAttributeNames object 属性名のプレースホルダを定義する。
5 FilterExpression string 検索後のフィルター条件を記述します。
  • 1~3はおそらく必須。 APIの説明ではTableNameだけ必須と書いてあるのですが、少なくともKeyConditionExpressionExpressionAttributeValuesを指定しないと実質的に検索できません。
  • 「4. ExpressionAttributeNames」は、検索する属性名に予約語が使われている場合に、読み替えを行うため必要となるパラメータ。
  • 他のパラメータについては、Query - Amazon DynamoDBで御確認ください。

KeyConditionExpression - キー、インデックスによる検索を定義する

KeyConditionExpressionにはキーによる検索の定義を、具体的な値を記述する替わりに検索値のプレースホルダを使って行います。 プレースホルダは、検索値に対する仮引数みたいなものです。

以下の :placeholderName の部分が検索値のプレースホルダ

{
    "KeyConditionExpression":
        "keyAttrName = :placeholderName",
}

具体的な検索値は次項の ExpressionAttributeValues で指定します。

ExpressionAttributeValues - 検索値のプレースホルダを定義する

ExpressionAttributeValuesには、KeyConditionExpressionやFilterExpressionに記述されているプレースホルダの値を型とともに指定します。

{
    "KeyConditionExpression":
        "keyAttrName = :placeholderName",
    "FilterExpression":
            "attrName > :placeholderName2",
    "ExpressionAttributeValues": {
        ":placeholderName":  { "S" : "11" },
        ":placeholderName2": { "N" : "12" }
    }
}

チュートリアルでは値だけが指定されていますが「structureじゃないとダメですよ」という例外が投入されます。

ExpressionAttributeNames - 属性名のプレースホルダを定義する

DynamoDBのテーブルの属性名に予約語が使われている場合、検索条件を記述できません(「属性名がキーワードだ」との例外投入) ので、ExpressionAttributeNamesで置き換えます。

以下の例では、予約語timestampと同じ属性名を、読み替えています。(#Tmの部分)

        "KeyConditionExpression": "#Tm = :T0",
        "ExpressionAttributeNames": {
            "#Tm": "timestamp"
        },
        "ExpressionAttributeValues": {
            ":T0" : { "S" : "" + event.t0 }
        }

他のAPI

テーブルの項目を操作するAPIは以下の様なものがあります。

  • 項目の問い合わせ - Query
  • 全項目取得 - Scan
  • 特定項目を取得 - GetItem
  • 項目上書き - PutItem
  • 項目変更 - UpdateItem
  • 項目削除 - DeleteItem
  • バッチ項目取得 - BatchGetItem
  • バッチ項目更新 - BatchWriteItem

  • PutItemとUpdateItemは紛らわしいけど、上書きしてしまうか、特定の属性の変更が行えるかの違いらしい(詳細不明)

  • バッチ系はちょっと使い勝手が違うかもしれませんが、一度にやっちゃう感じでしょう(詳細不明)
  • その他、テーブルを操作するAPIDynamoDBのAPIの説明ページ に書いてあります。

その他、一般事項

Node.jsから呼び出すAPIのメソッド名

DynamoDBのAPIの説明ページ に掲載されている API の名称をキャメルケースに変換すれば、Node.jsのメソッド名になると思います(多分)。

DynamoDB APIの基本形

Node.jsでのDynamoDB APIは、以下のような形式で呼び出します。

dynamo.apiName(params, function(err, data) {
    if(err) {
        //エラー;
    } else {

        //dataにAPIの実行結果が入っています。

    }
});

(↑)apiNameをAPIの名前に書き換え。


RDB技術者のためのNoSQLガイド
渡部 徹太郎 河村 康爾 北沢 匠 佐伯 嘉康 佐藤 直生 原沢 滋 平山 毅 李昌 桓
秀和システム
売り上げランキング: 40,238
広告を非表示にする