読者です 読者をやめる 読者になる 読者になる

銀の弾丸

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

npm「list-it」― コンソールへ列を揃えた表形式でのデータ表示を支援するモジュール

npm Node.js CLI

コンソールへの表形式でのデータ表示を支援するNode.jsのモジュール(npm)「list-it」のご紹介。

最近寝ても覚めてもnpmです(うそ)。

しかし、npmに慣れると楽しいのは確かですわ。 テストや環境の管理も便利なツールが揃っていて、気楽にコードが書けるのが良いのかも。

「npmコーディングクエスト」的な心境です。いくつになってもお勉強ですな。

f:id:takamints:20160501161451p:plain



駆け足でご説明するざっくりした使い方

  1. require("list-it")する。
  2. buffer()メソッドで空のバッファを作成。
  3. d()メソッドで、現在の行へ列(セル)データを追加。複数指定も可。
  4. nl()メソッドで現在行への列の追加を終了し次の行へ。
  5. 追加できるデータの型は文字列か数値。配列は行の追加になる(行追加時はnl()不要)
  6. 複数の配列を与えると複数の行が出来上がります。2次元配列でも可。
  7. toString()で文字列化してconsole.log()

機能の概要

上記のように、表形式のデータをポンポン放り込んで、あとから、整形された文字列を取り出すわけです。列の横位置が揃えられているので、そのままコンソールへ表示できます。

  • 複数カラムまとめてデータを追加できます。行によって列数が違っていてもかまいません。
  • 行単位での追加も可能。複数行もまとめて追加できます。
  • autoAlign(自動整列)モードONで、数値は小数点位置を揃えて右寄せ、文字列は普通に左寄せ。
  • 文字列データにはANSIエスケープシーケンス使用できます。ただし色やスタイルの指定のみです。カーソル移動とかは無理。エスケープシーケンスのリセットは自動では行いませんので自己責任でよろしくです(追加する文字列の最後にリセットシーケンスを入れておいてください)。
  • 日本語などの幅の広い文字も正しく処理できます(実は、これ書きながらバグに気付いて慌てて対応いたしましたw)

サンプルコードと出力例

japanese-foods.js

var listit = require("list-it");//①
var buf = listit.buffer();      //②
console.log(
    buf
        .d("1").d("Sushi")      //③
            .d("vinegared rice combined raw seafood")
            .d("Healthy").nl()  //④
        .d("2").d("Yakiniku")
            .d("Grilled meat on Japanese")
            .d("Juicy").nl()
        .d("3").d("Ramen")
            .d("Japanese noodle soup dish")
            .d("I like it").nl()
        .d("4").d("Tempura")
            .d("Deep fried seafood or vegetables")
            .d("Delicious").nl()
        .d("5").d("Sashimi")
            .d("Very fresh sliced fish")
            .d("Try it now, It's good").nl()
        .toString());

出力: 文字列は左寄せです

$ node sample/japanese-food.js
1 Sushi    vinegared rice combined raw seafood Healthy
2 Yakiniku Grilled meat on Japanese            Juicy
3 Ramen    Japanese noodle soup dish           I like it
4 Tempura  Deep fried seafood or vegetables    Delicious
5 Sashimi  Very fresh sliced fish              Try it now, It's good

autoAlign

bufferを生成するときに autoAlignオプションをtrueに指定しておくと、文字列化するときに、データの型を考慮してセルの整形を行います。

planets.js

var listit = require("list-it");
var buf = listit.buffer({ "autoAlign" : true });
var PLANETS = [
    ["NAME", "Mass(10^24kg)", "Dia(km)", "Dens(kg/m3)",
                        "Grav(m/s2)", "EscV(km/s)", "Rot(hours)" ],
    ["MERCURY", 0.33,   4879,   5427,   3.7,    4.3,    1407.6  ],
    ["VENUS",   4.87,   12104,  5243,   8.9,    10.4,   -5832.5 ],
    ["EARTH",   5.97,   12756,  5514,   9.8,    11.2,   23.9    ],
    ["MOON",    0.0073, 3475,   3340,   1.6,    2.4,    655.7   ],
    ["MARS",    0.642,  6792,   3933,   3.7,    5.0,    24.6    ],
    ["JUPITER", 1898,   142984, 1326,   23.1,   59.5,   9.9     ],
    ["SATURN",  568,    120536, 687,    9.0,    35.5,   10.7    ],
    ["URANUS",  86.8,   51118,  1271,   8.7,    21.3,   -17.2   ],
    ["NEPTUNE", 102,    49528,  1638,   11.0,   23.5,   16.1    ],
    ["PLUTO",   0.0146, 2370,   2095,   0.7,    1.3,    -153.3  ]
];
console.log( buf.d( PLANETS ).toString() ); //⑤、⑥

出力: 数値は小数点の位置を揃えて右寄せ

$ node sample/planets.js
NAME    Mass(10^24kg) Dia(km) Dens(kg/m3) Grav(m/s2) EscV(km/s) Rot(hours)
MERCURY        0.33      4879        5427        3.7        4.3     1407.6
VENUS          4.87     12104        5243        8.9       10.4    -5832.5
EARTH          5.97     12756        5514        9.8       11.2       23.9
MOON           0.0073    3475        3340        1.6        2.4      655.7
MARS           0.642     6792        3933        3.7        5.0       24.6
JUPITER     1898.0     142984        1326       23.1       59.5        9.9
SATURN       568.0     120536         687        9.0       35.5       10.7
URANUS        86.8      51118        1271        8.7       21.3      -17.2
NEPTUNE      102.0      49528        1638       11.0       23.5       16.1
PLUTO          0.0146    2370        2095        0.7        1.3     -153.3

日本語(ワイド文字)

japanese-foods-jp.js

var listit = require("list-it");
var buf = listit.buffer();
console.log(
    buf
        .d("1").d("寿司")
            .d("酢とご飯とシーフード")
            .d("健康的だ").nl()
        .d("2").d("焼肉")
            .d("日本のグリルされたお肉")
            .d("ジューシー").nl()
        .d("3").d("ラーメン")
            .d("日本のスープに入った麺")
            .d("大好き").nl()
        .d("4").d("天ぷら")
            .d("シーフードや野菜に衣をつけて揚げたもの")
            .d("おいしー").nl()
        .d("5").d("刺身")
            .d("大変フレッシュな魚のスライス")
            .d("食べてみて!あご落ちるぜ").nl()
        .toString());

出力: HTMLでは何故か微妙にズレるけどコンソールではズレてません。

$ node sample/japanese-food-jp.js
1 寿司     酢とご飯とシーフード                   健康的だ
2 焼肉     日本のグリルされたお肉                 ジューシー
3 ラーメン 日本のスープに入った麺                 大好き
4 天ぷら   シーフードや野菜に衣をつけて揚げたもの おいしー
5 刺身     大変フレッシュな魚のスライス           食べてみて!あご落ちるぜ

未実装機能(将来追加する可能性はあり…ます…)

  • 文字列の折り返しができるようになればいいな。列幅指定してとか、コンソールの幅を判別して、自動的に列を折り返すとかできると超クール。
  • 見出し行とか見出しセルの概念を、我、欲す。行、列、セル単位でスタイル指定したい。
  • 表を転置(トランスポーズ:行列入れ替え)したいときがたまにある。
  • 演算機能があってもよいかなとか。あ、行列演算できてもよいか?いや、それはやりすぎか。

リポジトリ

メソッドの詳細などは、以下のリポジトリにあります。どう考えてもおかしな結果が得られたって時は、バンバンIssue入れてください。

GitHub

github.com

npm

www.npmjs.com

その他

これ、結構需要がある気がしていますが、プロジェクト単位でガチガチに力技で作ったりしがちですよね。 また、こういったモジュールは既にあるのかもしれませんが、軽く検索して見つけられなかったので作りました。

npmにはまる以前に作っていた別ソフトがベースになっています。 当時必要だと感じていた機能以上に、あれもこれもとドンドン実装したくなるから面白いもんですね。

npm 「hash-arg」 ― コマンドラインパラメータに名前でアクセス

Node.js CLI npm コマンドラインパラメータ node_modules JavaScript

コマンドラインで指定されたパラメータに名前でアクセスする為の、シンプルなNode.jsのモジュール hash-argをnpmで公開したので御紹介します。

npm便利ですね。若干敷居が高い気がしていましたが、まずはいろんなモジュールを検索して使うところから始めるといいですね。

f:id:takamints:20160403163627p:plain

'hash-arg'コマンドラインパラメータに名前でアクセスするためのシンプルなnpmモジュールです。

www.npmjs.com

ソースはGitHibに置いています。

github.com


JavaScript 第6版
JavaScript 第6版
posted with amazlet at 16.04.03
David Flanagan
オライリージャパン
売り上げランキング: 16,569

はじめに

このモジュールは、コマンドラインオプションの処理をするものではありません

単純に、コマンドライン引数、または配列の各要素に、前から順に名前を付けてハッシュ(JavaScriptのobject)を返すモジュールです。 追加の機能として、各パラメータの型指定と、省略時の既定値の指定ができますが、基本的には単純なものです。

Node.jsのコマンドラインパラメータは、process.argv[2] 以降に文字列として格納されています([0][1]"node"と、スクリプト名)から、本モジュールにパラメータの定義(名前、型、既定値)だけを与えた場合は、process.argv[2]以降の要素を処理対象とします。 別の配列を与えた場合は、すべての要素を処理します。

オプションが含まれる場合

コマンドライン引数に'-'で始まるようなオプションを含ませたい場合は、先にnode-getoptのようなオプションのパーサーで処理しておいて、そのモジュールが(おそらく)提供している、「オプションではない引数の配列」を、当モジュールで処理させます。

少しだけ気楽になるモジュールです(多分)

オプションではない引数が配列に入っている場合、その要素数をチェックして、必要なパラメータが足りていなかったりすると、エラーにしたり、省略時の既定値を設定したりしますよね。これって、少し邪魔くさい。

本来ザクザク書きたいのはそういうところじゃないはずです。 どの位置に何が指定されていたのか?という情報は、その後、使わない情報ですし。

あと、最初のパラメータなのにprocess.argv[2]とか書いちゃうあの妙な違和感(笑)もどうにかできます。

使い方:単純に'process.argv'を使用する場合

唯一のメソッドgetの第一引数にパラメータ名の定義を与えて呼び出せば、process-argvから値を取り出し、オブジェクトの指定されたキーに値を格納して返します。 (第二引数は省略可能なパラメータの配列です)

simple.js

args = require("hash-arg").get(
        "inputFilePath outputFilePath");
 
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/simple.js input.json output.json
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json"
}

使い方:node-getoptのようなコマンドラインパーサーと共に使用

省略可能な第二引数に、たとえば、node-getoptモジュールの argv プロパティを与えればOK。

with-node-argv.js

getopt = require("node-getopt").create([
    ['s', '', 'short option'],
    ['l', 'long', 'long option'],
    ['S', 'short-with-arg=ARG', 'option with argument']
]).parseSystem();
 
args = require("hash-arg").get([
        "inputFilePath",
        {
            "name":"outputFilePath",
            "default": "out.json"
        }
        ], getopt.argv);
 
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/with-node-getopt.js -S DUMMY input.json -sl output.json
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json"
}

GET メソッド

呼び出し形式

HashArg.get(<argument-def> [, <argv-source-array>]);

argument-def

パラメータの定義を行う。

単一の文字列、または、文字列配列、または、パラメータ定義オブジェクトの配列を指定できる。

1) 文字列の場合

パラメータのキー名称をスペースで区切った文字列

例)

"inputFilePath outputFilePath"

2) Array of string

各要素がパラメーター名である文字列の配列。

例)

["inputFilePath", "outputFilePath"]

3) Array of definition object

このフォーマットでは、省略時のデフォルト値を指定できます。

デフォルト値が指定されていない場合は、nullが使用されます。

[
    {"name":"inputFilePath"},
    {
        "name"      : "outputFilePath",
        "default"   : "out.json"
    }
]

argv-source-array (省略可能)

コマンドラインパラメータを保持する文字列配列。

省略時はprocess.argvが使われます。

※ 注意:v0.0.2以前では、getの第二引数に、process.argvを与えると誤動作します。

定義より多くパラメータが指定されたら

v0.0.3以上では、パラメータ定義の数よりもコマンドラインで指定されたパラメーターが多い場合、未定義のパラメータが、返されるオブジェクトの空文字のキーに配列として保存されます(v0.0.2以前ではそれらは失われていました)。

args = require("hash-arg").get("inputFilePath outputFilePath");
console.log(JSON.stringify(args, null, "  "));

実行例:

$ node test/with-node-getopt.js input.json output.json foo bar
{
  "inputFilePath": "input.json",
  "outputFilePath": "output.json",
  "": ["foo", "bar"]
}

ライセンス

MIT

その他

単に利用するだけなら、npm install hash-argでOKですよ。


Node.jsで正常終了:process.exit(0) は呼ばないほうが良いですね

Node.js CLI JavaScript

「ダメ!絶対!」ということでも無いですが、Node.jsで、正常終了するとき、process.exit(0)と明示的に呼び出さないほうが良いですねっていう小ネタです。

※ ↓小ネタの割には土曜の朝からガッツリInkscapeしばいてました(笑)

f:id:takamints:20160402113544p:plain



勢い余って呼んじゃったんですよ

最近Node.jsでコマンドラインツールを書くことが多いのです。 エラー処理とかキチンと書いて、かっこよくエラーメッセージなんか出しちゃったりしてご満悦。 「それじゃあ、ここでお父さん、終了コード1で終わっちゃうぞー」みたいにノリノリです。

で、勢い余って最後の行に「ここは正常終了ですよー」とニコヤカに、ついつい process.exit(0) と書いてしまった

その結果、「正常終了しているけれど、処理が正しくできてない」という、「おい!どうなってんだ?」ってな状況に困惑。わけわからん。

以下のようなコードです。(※ 実際はもっと複雑ですけどね)

var fs = require("fs");
if(process.argv.length < 2) {
    console.error("エラー:ファイル名なし");
    process.exit(1);
}
fs.readFile(process.argv, "utf-8", function(err, data) {
    //
    //ファイルを読み込んであれこれする
    //
});
process.exit(0); //ここで正常終了ね

process.exitは「非同期ではない」

もうお気づきでしょうか、最後の行です。

これだと readFileのコールバックが呼ばれる前に、プロセスが正常終了しちゃいますね。

「nodeのプロセスは、全てのコールバックが終わってから終了する」けど、明示的にprocess.exitを呼び出したら、その時点で終了してしまいます。

これは当然の仕様で、そうでなきゃ困るんだけど、意識してなかった。

ダメ!絶対!興味本位で呼び出さないで!

ということで早速結論

Nodeのスクリプトで正常に処理を終了するときは、process.exitを呼び出さないほうが良い。

呼び出さなければ全部の処理を確実に実行してから、自動的に終了コード=0で終了してくれますが、 呼び出していると「これ、本当に全部の処理が行われてから正常終了しているの?」と疑うことが出来てしまいます。 コードレビューで指摘されると正統性を示すのが結構大変になりそうですし。

よく「呼び出す必要が無い」と説明されているのですが、もうチョット強めのニュアンスの方が良いのではないかと思います。 興味本位で呼んでしまう人っていると思うんですよ。

おまけ:0以外の終了コードで正常終了する方法

じゃあ0以外の終了コードで正常終了を表したい場合は、どうすればいいの?って思いますよね。

以下のようにすると良いですよ。

process.on("exit", function() {
    process.exit(1);
});

確認してみる。


$ node -e "process.on('exit', function(){process.exit(255);});"

$ echo $?
255

$

OKですね。


Nodeクックブック
Nodeクックブック
posted with amazlet at 16.04.02
David Mark Clements
オライリージャパン
売り上げランキング: 277,422

AWS Lambdaの関数アップロードをお手軽に

AWS AWS Lambda Linux / Bash Node.js npm

Lambda関数を、ローカルPCからアップロードするコマンドをご紹介。ダウンロードも出来ますよっと。

Lambda関数はAWSのWEBコンソールで編集できますが、数が増えるとやってらんない。そして外部モジュールを使う場合はWEBでは無理ですし。

でき得るならばローカルで、編集したのをアップロードしたいのだけど、その都度ZIPしてアップしてとか、それはそれで手間がかかってイライラします…

f:id:takamints:20160309213632p:plain
photo credit: 150120-N-ZZ999-002 via photopin (license)

てなことで、怒りに任せて(笑)取り急ぎ、勢いで3つばかり作ってしまいました。

追記:その後コマンド追加したり手直しして、npmにaws-node-utilという名で登録しています。

以下のメニューで御説明。

目次

  1. コマンド
    1. aws-lambda-get - Lambda関数をダウンロード
    2. aws-lambda-upload - Lambda関数を更新(上書き)
    3. aws-lambda-create - Lambda関数を新規作成
  2. 機能説明
    1. ローカルのLambda関数のディレクトリ構造
    2. アップロード前に特定の処理を実行する
  3. セットアップ
    1. 実行環境と必要なツール
    2. インストール方法
    3. リポジトリ


1. コマンド

1-1. aws-lambda-get - Lambda関数をダウンロード

AWSのLambda関数をダウンロードします。

$ aws-lambda-get <function-name>

パラメータ

  • function-name - Lambda関数名。

ちゃんとダウンロードできたら、カレントディレクトリに関数名のディレクトリが作られ、全てのファイルが展開されます。

安心してください、上書きしませんよ

既に同名のサブディレクトリがカレントディレクトリ直下にある場合はダウンロードしません。 ディレクトリの名前を変更して再実行してください。

1-2. aws-lambda-upload - Lambda関数を更新(上書き)

AWSのLambda関数をローカルファイルで更新します。

カレントディレクトリ直下の関数名のディレクトリをZIPファイルにまとめてAWSへアップロードして上書きます。

$ aws-lambda-upload <function-name>

パラメータ

  • function-name - Lambda関数名。カレントディレクトリ直下に同名のサブディレクトリが必要です。それをZIPしてアップします。

1-3. aws-lambda-create - Lambda関数を新規作成

ローカルのLambda関数をAWSへアップロードし、新規作成します。

カレントディレクトリ直下の関数名のディレクトリをZIPファイルにまとめてAWSへアップロードします。

$ aws-lambda-create <function-name> <role-arn>

パラメータ

  • function-name - Lambda関数名です。カレントディレクトリ直下に同名のサブディレクトリが必要です。それをZIPしてアップします。
  • role-arn - Lamdaに付けられるRoleのarnを指定してください。RoleはAWS IAMで作成出来ます。

Node.js限定です

新規作成に関しては、言語はnode.jsだけで、ハンドラーは index.handlerに固定されています。

生成だけなら別途awsコマンドでやってもたいした手間ではありません。その後、uploadすれば大丈夫なんじゃないかな?(試してないのでスミマセン)

2. 機能説明

2-1. ローカルのLambda関数のディレクトリ構造

AWSからダウンロードするとカレントディレクトリ直下に関数名のサブディレクトリが作成されます。 このディレクトリは、そのままアップロードできる状態になっています。

たとえば、以下のようにHelloLambdaという関数をダウンロードすると、 カレントディレクトリ直下にディレクトリHelloLambdaが作成され、全ファイルが展開されます。

$ aws-lambda-get HelloLambda

以下は、HelloLambdaがモジュールを使用している場合の例です。

./HelloLambda/
    index.js
    node_modules/
      node-uuid/
        ....

2-2. アップロード前に特定の処理を実行する

アップロードする前に、Lambda関数が利用しているモジュールを更新したり、エディタのテンポラリファイルを削除したくなると思います。

各関数のディレクトリ直下に、.onupload.sh というファイルがあれば、アップロード前(正確にはZIPで固める前)に、これをシェルスクリプトとして実行します。

このファイル自体はAWSへはアップロードされません。

#node-uuidをインストール
if [ ! -d node_modules ]; then
    npm install node-uuid
else
    npm update node-uuid
fi
#VIMのバックアップファイルを消す
rm *~ .*~ 

3. セットアップ

3-1. 実行環境と必要なツール

利用するには、以下のものが必要です。

  • AWSのアカウント - これがないと始まらない。今なら登録から1年間は基本的に無料。
  • AWSCLI - AWSコマンドラインインターフェースです。AWSからダウンロードしてインストールし、AWSアカウントで接続できるようにしておいてください。各コマンドから利用しています。
  • Bash - コマンドがシェルスクリプトなので必要です。
  • Node.js - JSONの処理等に利用しています。将来的には全部Nodeでやりたいです。
  • Zip/Unzipコマンド - Lambda関数のアップロード、ダウンロードで必要になります。(Bashで最初から利用できるのかも?)

3-2. インストール方法

npmにpublishしたので、インストールは npm install -g aws-node-utilでOKです。

インストールスクリプトINSTALL.sh

$ sh INSTALL.sh

実行すると、各スクリプト~/binへコピーし、node_modules以下のファイルを ~/node_modules へコピーしています。

かなりいい加減なインストールスクリプトで申し訳ないです。当方MinGW使ってるのでこれで済んでいます。

可能ならば、Forkして適切に修正してください。そしてプルリク下さい。よろしくお願いいたします。

3-3. リポジトリ

ソースは全て以下のGitHubに置いています。 ご自由に利用なさってください(MIT license)。 他にも雑多なスクリプトが入っていますが、それはそれでまたおいおい。

github.com

AWS LambdaからDynamoDBをQueryする

AWS AWS Lambda AWS DynamoDB Node.js

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文字列を出力しています。

AWS 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