ja ja en nb ja cs ja ja ja ja ja ja ja ja ja ja en ja en ja en ja ja ja ja ja ja en ja ja ja ja ja en ja ja en zh ja vi ja ja de ja ar ja zh ja pt ja en en ja ja ja en de ja en nb ja en ja ja zh ja ja ja ja ja en nl ja nb ja ja pl en ja nb ja ja nb ja ja nb ja ja ja ja ja en ja ja ja ja ja ja ja ja ja ja ja ja ja ja ja jbo en en ja nl nb en ko it en it it it en fr it ja ja en la fi ja it it it pt it de en ja en en it fr it en it nb it ja ja ja ja en ja ja ja ja ja ja ja ja ja
Node.js+Dynamo DBでレコードを検索する - Sanwa Systems Tech Blog
もともとDnyamoDBをJavaScriptから利用するためのSDKとしてはAWS.DynamoDBというクラスがあるのですが(後述)、検索時に値の型を明示する必要があったりしてあまり使いやすいとは言えません。たとえば検索時や新規レコード挿入時に"ABC"という文字列を与えるのにもいちいち{"S" : "ABC"}というハッシュ(Sは文字列を意味するラベル)として渡す必要がありますし、逆に検索結果に"ABC"という文字列が含まれていても、結果は{"S" : "ABC"}というハッシュで返ってきます。
scan()に渡すパラメーターに条件を追加してあげれば検索ができます。たとえばSQLで SELECT * FROM TABLENAME WHERE num = 10 に相当する検索を行いたければこうなります。
var param = { TableName : "TABLENAME", FilterExpression : "num = :val", ExpressionAttributeValues : {":val" : 10} }; dynamo.scan(param, function(err, data) { ... }
FilterExpressionでプレースホルダーを埋め込んだ条件式を与える
実際の値をExpressionAttributeValuesで与える
と検索ができる、というだけの簡単な仕組みです。どのキーでも検索対象とできますが、文字通りのスキャンなので検索コストが跳ね上がる可能性があります。インデックスを追加して検索に使えるようにしてあげるというお馴染みの手法で改善を図れます。
query()で検索・その1
scan()のかわりにquery()を呼んでも検索ができます。ただし今度の検索条件にはプライマリキーの指定が必須となります(不自由な分だけ低コストです)。たとえばSQLで SELECT * FROM TABLENAME WHERE key = 'A' に相当する検索ならこうなります。
var param = { TableName : "TABLENAME", KeyConditionExpression : "#k = :val", ExpressionAttributeValues : {":val" : "A"}, ExpressionAttributeNames : {"#k" : "key"} }; dynamo.query(param, function(err, data) { ... }
KeyConditionExpressionでプレースホルダーを埋め込んだ条件式を与える
実際の値をExpressionAttributeValuesで与える
検索するプライマリキー・セカンダリキー名にkeyやFILEといった予約語 を使っている場合はエラーになる
#から始まる適当な別名(上の例では#k)を付けて、その実際のキー名をExpressionAttributeNamesで与えることで回避できる
プライマリキーが条件に含まれていれば、セカンダリキーを追加で指定することもできます。
var param = { TableName : "TABLENAME", KeyConditionExpression : "#k = :val and key2 >= :val2", ExpressionAttributeValues : {":val" : "A", ":val2" : "Q"}, ExpressionAttributeNames : {"#k" : "key"} }; dynamo.query(param, function(err, data) { ... }
query()で検索・その2
query()はKeyConditionExpressionではなくKeyConditionという別の形のパラメーターも受け付けます。ただ、こちらは冗長で読みづらいだけでなく、ドキュメントに「古いやり方なのでもう使うな」とあるため使用は避けるべきでしょう*2。上と同じ検索を行うコードは次の通りです。
var param = { TableName : "TABLENAME", KeyConditions : { key : { ComparisonOperator : "EQ", AttributeValueList : {S : "A" } }, key2 : { ComparisonOperator : "GE", AttributeValueList : {S : "Q" } } } };
get()はレコード1件だけを取得するためのメソッドです(内部的にはAWS.DynamoDB.getItem()を呼び出します)。つまり検索条件からレコードを特定できないといけないので、プライマリキーの指定は必須、テーブルにセカンダリキーが存在する場合はセカンダリキーの指定も必須になります(そうしないと"The provided key element does not match the schema"と言われてエラーになります)。パラメーターの形はだいぶ違いますがその分だけシンプルになります。
var param = { TableName : "TABLENAME", Key: { key : "A", key2: "Q" } }; dynamo.get(param, function(err, data) { ... }
大文字のKeyは検索条件を示します。
小文字のkey, key2はテーブルのプライマリキー・セカンダリキーの名前です。
batchGet()で検索
内部的にはAWS.DynamoDB.batchGetItem()を呼び出します。検索レコード数が多いときなど、ページングを行うにはこちらのメソッドを使う必要があります。今回は省略します。
上述のAPI、つまりAWS.DynamoDBを直接呼び出すこともできます。全件検索はこうなります。
var AWS = require("aws-sdk"); var dynamo = new AWS.DynamoDB(); exports.handler = function(event, context) { dynamo.scan({TableName : "TABLENAME"}, function(err, data) { if (err) { context.fail(err); // エラー時 } else { context.succeed(data); // 正常時 } }); };
2行目を除いてDocumentClientの例と全く同じです。ただし結果の形式が異なり、フィールドの型が明示的に指定されます。ドキュメントの中でも言及されている通り、数値(整数・実数)の区別があるため厳密ですが、状況によっては使いづらいかもしれません。
{ "Items": [ { "key": { "S": "A" }, "key2": { "S": "P" }, "str": { "S": "ap" }, ...
現時点でAPIのバージョンには2012-08-10版と2011-12-05版の2種類があり、どちらかを明示的に指定することもできますが、古い方をあえて指定するメリットはなさそうです。省略すれば新しい方になります。
var AWS = require("aws-sdk"); var dynamo= new AWS.DynamoDB({apiVersion: '2012-08-10'});
FilterExpressionが使えます。
var param = { TableName : "TABLENAME", FilterExpression : "num = :val", ExpressionAttributeValues : {":val" : {N : "10"}} // 数値の10を指定するときの書き方 }; dynamo.scan(param, function(err, data) { ... }
ScanFilterも使えます。
var param = { TableName : "TABLENAME", ScanFilter : { num : { ComparisonOperator : "EQ", AttributeValueList : [{N : "10"}] } } }; dynamo.scan(param, function(err, data) { ... }
ドキュメントにはKeyConditionExpressionが使えると書いてあるのですが、エラーになってうまくいきませんでした。KeyConditionsなら動きます(ただしDocumentClient版とは微妙にパラメーターの形が違います。AttributeValueListには配列を渡さなければなりません)。
var param = { TableName : "TABLENAME", KeyConditions : { 'key' : { ComparisonOperator : "EQ", AttributeValueList : [{S : "A"}] // ←配列 }, 'key2' : { ComparisonOperator : "GE", AttributeValueList : [{S : "Q"}] // ←配列 } } }; dynamo.query(param, function(err, data) { ... }
getItem()で検索
DocumentClientと同じ形で検索条件を渡せば同じ結果が返ってきます。
var param = { TableName : "TABLENAME", Key: { key : {S : "A"}, key2: {S : "Q"} } }; dynamo.getItem(param, function(err, data) { ... }
dynamodb-docを使う
Lambdaのblueprintで"DynamoDB"が名前に付くものを探すといくつか候補が出てきますが、この中で使われているものです。
var doc = require('dynamodb-doc'); var dynamo = new doc.DynamoDB(); exports.handler = function(event, context) { dynamo.scan({TableName : "TABLENAME"}, function(err, data) { if (err) { context.fail(err); // エラー時 } else { context.succeed(data); // 正常時 } }); };
dynamodb-document-js-sdk だと思われますが、こちらはNOTEに記載されている通り今後はメンテナンスされません。使わない方が無難だと思われます。
DynamoDBのAPIはずいぶん長い間放っておかれていたように思っていたのですが、そのせいか古い情報がまだ数多く残っています。ドキュメントを熟読するのは大切だなあと思った一コマでした。
*1:サイズ制限があり、それを超えた分はページングで取得する必要がありますが、今回は省略します
*2:なおDocumentClientのドキュメントにはKeyConditionExpressionの説明しか載っていません。KeyConditionの説明はAWS.DynamoDBのドキュメントにあります
nurenezumi 2016-01-20 14:35
LINEのMessaging API WebhookをAPI Gatewayで受ける
こんにちは、AWS担当のwakです。 最近LINE botがMessaging API…
API Gateway + LambdaでSlackのCustom Commandを作る
こんにちは、AWS担当のwakです。先日このような記事を書いたの…
AWS LambdaからGoogle APIを呼び出す
こんにちは、AWS担当のwakです。間が空いてしまったので、今回…
ASP.NET Web APIでログを綺麗に出す
井上です。 Web Request/Responseのログをお手軽に出しましょう…
AWS LambdaのパラメータをDynamoDBで管理する
こんにちは、AWS担当のwakです。前回に続きAWS Lambdaの話をし…
« AWS LambdaのパラメータをDynamoDBで管理… AWS LambdaでWebサイトの死活監視を行って… »