質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

Q&A

解決済

1回答

6219閲覧

DynamoDBに複数の項目を追加するプログラムでcontext.done()をコールするタイミングがわかりません

akabei

総合スコア21

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

AWS(Amazon Web Services)

Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

0グッド

0クリップ

投稿2016/03/28 11:13

編集2016/03/29 12:47

AWSのLambdaでS3にアップロードされたJSONファイルを読み込んで
その内容をDynamoDBへ書き込むプログラムを作成しています。

JSONファイルには複数のデータがありこれを全てDynamoDBへ書き込みます。

以下が作成したソースコードとJSONファイルの内容です。

JavaScript

1console.log('Loading function ...'); 2 3var aws = require('aws-sdk'); 4var s3 = new aws.S3({ apiVersion: '2006-03-01' }); 5var dynamo = new aws.DynamoDB({region: 'ap-northeast-1'}); 6 7//読み込んだJSONをDynamoDBのパラメータ形式に変換 8function getItemList(table) { 9 var items = []; 10 for (var i = 0; i < table.length; i++) { 11 var item = {}; 12 var record = table[i]; 13 console.log(record); 14 for (var column in record) { 15 item[column] = {'S': record[column]}; 16 } 17 items[i] = item; 18 } 19 return items; 20} 21 22exports.handler = function(event, context) { 23 //console.log('Received event:', JSON.stringify(event, null, 2)); 24 //S3からJSONファイルを読み込む 25 var bucket = event.Records[0].s3.bucket.name; 26 var key = event.Records[0].s3.object.key; 27 console.log('Bucket:', bucket, ' Key:', key); 28 s3.getObject({Bucket: bucket, Key: key}, function(err, data) { 29 if (err) { 30 console.log(err); 31 context.fail('S3 object get error!! ' + err.code + ":" + err.message); 32 } 33 else { 34 //テーブル名 35 var tablename = 'test'; 36 37 //読み込んだJSONをDynamoDBのパラメータ形式に変換 38 var content = JSON.parse(String(data.Body)); 39 console.log('Table:', tablename, ' Count:', content[tablename].length); 40 var items = getItemList(content[tablename]); 41 for (var i = 0; i < items.length; i++) { 42 var params = { 43 TableName: tablename, 44 Item: items[i] 45 }; 46 //DynamoDBへ書き込む 47 dynamo.putItem(params, function (err, data) { 48 if (err) { 49 console.log(err); 50 context.fail('DynamoDB put error!! ' + err.code + ':' + err.message); 51 } 52 else { 53 console.log('data uploaded successfully.'); 54 //★1)doneを呼び出すタイミングは? 55 //context.done(); 56 } 57 }); //★2)ワーニング: Don't make functions within a loop. 58 } 59 } 60 }); 61}

JSON

1{ 2 "test": [ 3 { 4 "id": "1", 5 "key": "000001", 6 "data1": "abcdefg" 7 }, 8 { 9 "id": "2", 10 "key": "000002", 11 "data1": "abcdefg", 12 "data2": "ABCDEFG" 13 }, 14 { 15 "id": "3", 16 "key": "000003", 17 "data1": "abcdefg", 18 "data2": "ABCDEFG", 19 "data3": "1234567" 20 } 21 ] 22}

動作するのは確認できたのですが、わからない点が2つあります。

★1) DynamoDBへ書き込む際、複数回putItem()をコールしたときcontext.done()をコールするタイミングがわからない。
★2) putItem()のfunctionでワーニングが発生してしまいます。functionはループ内に作成してはいけないようですがどのように修正したらよいでしょうか?

context.done()はコールしなくてもよいのか?全ての書き込みが終了したことを判断する方法が別にあるのでしょうか?
functionは別に分けてみましたがcontextが参照できなくなってしまいました。

BatchWriteItem()で一度にまとめて書き込めることは分かったのですが
今回のように引数にfunctionをもつ関数を複数回コールしたいときどのようにプログラムするのがいいのでしょうか?

同様のプログラムを作成された方がいましたら
教えていただけると助かります。

追記)
★2はコードをテキストファイルにコピーして貼り付けなおしたところワーニングは消えました。
これでいいのかわかりませんが・・・。
引き続き★1について何かわかることがあれば教えて下さい。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

DynamoDBについての知識はないです(この質問でしったくらい)が、JavaScriptの知識だけで回答してみます

まず、コールの必要性ですが、ググると Amazon の公式ぽいところに

Important

Lambda 関数の実行を正しく終了させるためには、context.succeed()、context.fail()、または context.done() メソッドを呼び出す必要があります。どのメソッドも呼び出していない場合、Node.js のイベントキューが空になるか、または Lambda 関数がタイムアウトするまで、Lambda 関数は実行を続けます。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/nodejs-prog-model-context.html

とあったので、successfail も呼ばないときは呼び出したほうがいいのでしょう
実行終わったら Node.js が終了するから不要な場合もあるかもですけど、大抵の場合はそうじゃないと思います

呼び出す場合ですが、これまたぐぐってみると、putItem の後のコールバックの中で context.done を呼び出している例がいくつかありました
putItem を複数実行している場合は全部のコールバックが終わったときに、context.done() を呼べばいいと思います

for 文の前に length を保存しておいて 各コールバックの中で 1 ずつ減らしていき、 0 になったら最後の処理を呼び出すというのが簡単な方法かと思います

ですが、こんなときの Promise.all なのかなと思ったので for (var i = 0; i < items.length; i++) { のところを Promise 化してみました

javascript

1Promise.all(items.map(item => { 2 return new Promise((resolve, reject) => { 3 var params = { 4 TableName: tablename, 5 Item: item 6 }; 7 //DynamoDBへ書き込む 8 dynamo.putItem(params, function (err, data) { 9 if(err) { 10 console.log(err); 11 context.fail('DynamoDB put error!! ' + err.code + ':' + err.message); 12 } else { 13 console.log('data uploaded successfully.'); 14 resolve(data); 15 } 16 }); 17 }); 18})).then(_ => { 19 context.done(); 20})

シンタックスしかチェックしてないです

投稿2016/03/29 13:43

ryls-nmm

総合スコア633

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

akabei

2016/03/30 07:28

回答ありがとうございます。 教えていただいた方法で試したり調べたことで不明点が明確になりました。 ・Promiseを使用してcontext.done()を呼び出せばいい。 ・Promiseの使い方が理解できていない。 ・Lambdaで直接コードを記述するとPromiseが使用できないので、外部モジュールをzipにまとめてアップロードする必要がある。 ・npmコマンドで外部モジュールをパッケージ化できる。 Node.js、Javascript、AWSとまだまだ勉強不足のまま手をつけてしまったのが良くなったようです。 教えていただいた内容から 参考になるサンプルコードも見つけることもできましたので 基本的なところから勉強しなおして見ようと思います。 大変参考になりました。ありがとうございます。
akabei

2016/03/31 02:01

以下のコードで動作することを確認できました! ```JavaScript new Promise(function(resolve, reject){ for (var i = 0; i < items.length; i++) { //console.log(items[i]); var params = { TableName: tablename, Item: items[i] }; //DynamoDBへ書き込む dynamo.putItem(params, function (err, data) { if (err) { reject(err); } else { resolve(data); } }); } }).then(function(data) { console.log("DynamoDB put success.", data); context.done(); }).catch(function(err) { console.log(err); context.fail("DynamoDB put error!! " + err.code + ":" + err.message); }); ``` Promise.allはまだ勉強不足で使用していませんがこれから勉強して使えるようにしたいと思います。 あらためてありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問