LambdaでDynamoDBのデータを操作する(Node&Python)

# はじめに

最近はもっぱらIoT関連の案件を担当しています。
AWSを使っているので、DynamoDBにデバイスからのデータを溜め込んだり、そのデータを取得して可視化したりなどすることが多く、その際にはLambdaが大活躍しています。
主にNode.jsを使っており、案件に応じてPythonでも実装をしていて、自分の中でテンプレート化してきたなーと思ったのでまとめておこうっとな。

## DynamoDBにデータをPutする
主にデバイスから受けとったデータをDynamoDBに書き込みます。
本来であればデータを加工する必要がありますが、そこはデバイスによって多種多様ですので割愛します。
ここで重要なのは、PartitionKeyとSortKeyの指定です。
ここを間違えてしまうとエラーを吐いてきます。(Key情報が間違ってるぜ！的な感じ) 

### Node.js

```js
const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
  region: "ap-northeast-1" // DynamoDBのリージョン
});

exports.handler = (event, context, callback) => {
  const params = {
    TableName: "table-name" // DynamoDBのテーブル名
    Item: {
      "PartitionKey": "your-partition-key-data", // Partition Keyのデータ
      "SortKey": "your-sort-key-data", // Sort Keyのデータ
      "OtherKey": "your-other-data"  // その他のデータ
    }
  }
  
  // DynamoDBへのPut処理実行
  dynamoDB.put(params).promise().then((data) => {
    console.log("Put Success");
    callback(null);
  }).catch((err) => {
    console.log(err);
    callback(err);
  });
}
```

### Python

```py
import boto3

def lambda_handler(event, context):
  try:
    dynamoDB = boto3.resource("dynamodb")
    table = dynamoDB.Table("table-name") # DynamoDBのテーブル名
    
    # DynamoDBへのPut処理実行
    table.put_item(
      Item = {
        "PartitionKey": "your-partition-key-data", # Partition Keyのデータ
        "SortKey": "your-sort-key-data", # Sort Keyのデータ
        "OtherKey": "your-other-data"  # その他のデータ
      }
    )
  except Exception as e:
        print e
```

## DynamoDBのデータを取得する(query)
主にDynamoDB内のデータを取得する際にはqueryを使います。
PartitionKeyだけでなくSortKeyもDynamoDBにあれば、ScanIndexForwardをfalseにLimitで取得した件数を指定して、降順(最新)のデータから固定の件数を取得することができます。
よく多いパターンとしては、あるDeviceID(PartitionKey)が送信してきたデータを最新から○○件取得したいなどのパターンがあります。

### Node.js

```js
const AWS = require("aws-sdk");
const dynamoDB = new AWS.DynamoDB.DocumentClient({
  region: "ap-northeast-1" // DynamoDBのリージョン
});

exports.handler = (event, context, callback) => {
  const params = {
    TableName: "table-name" // DynamoDBのテーブル名
    KeyConditionExpression: "#PartitionKey = :partition-key-data and #SortKey = :sort-key-data", // 取得するKey情報
    ExpressionAttributeNames: {
      "#PartitionKey": "your-partition-key", // PartitionKeyのアトリビュート名
      "#SortKey": "your-sort-key" // SortKeyのアトリビュート名
    },
    ExpressionAttributeValues: {
      ":partition-key-data": "your-partition-key-data", // 取得したいPartitionKey名
      ":sort-key-data": "your-sort-key-data" // 取得したいSortKey名
    }
    ScanIndexForward: false // 昇順か降順か(デフォルトはtrue=昇順)
    Limit: 1 // 取得するデータ件数
  }
  
  // DynamoDBへのquery処理実行
  dynamoDB.query(params).promise().then((data) => {
    console.log(data);
    callback(data);
  }).catch((err) => {
    console.log(err);
    callback(err);
  });
}
```

### Python

```py
import boto3
from boto3.dynamodb.conditions import Key

def lambda_handler(event, context):
  try:
    dynamoDB = boto3.resource("dynamodb")
    table = dynamoDB.Table("table-name") # DynamoDBのテーブル名
    
    # DynamoDBへのquery処理実行
    queryData = table.query(
      KeyConditionExpression = Key("your-partition-key").eq("your-partition-key-data") & Key("your-sort-key").eq("your-sort-key-data"), # 取得するKey情報
      ScanIndexForward = False, # 昇順か降順か(デフォルトはTrue=昇順)
      Limit = 1 # 取得するデータ件数
    )
    return queryData
  except Exception as e:
        print e
```

## さいごに

DynamoDBにはよくPutとqueryでデータを扱うことが多いので二つの方法についてまとめました。
場合によってはPutじゃなくてUpdateでなければならなかったり、とりあえず全件取得したいということきはscanを使ったりします。
ちゃんと***LambdaにDynamoDBを操作できるポリシーを持たせておくのを忘れずに！***
またquery実行時にときたま発生するのですが、「エラーが吐かれずに処理が完了したように見えるのに、DynamoDBにデータが入ってない！」見たいなことがあります。そんなときは***タイムアウトを疑ってください。***デフォルトでは3秒なので、queryで取得するデータの件数が多い場合はタイムアウトしてしまいます。
これはLambdaの中で使うように書きましたが、普通にSDKを使っているだけなので、WebアプリケーションやSDKを積めるデバイスからデータを扱う場合でも、上記のソースコードを改造すれば使えると思います。

余談ですが、Node書いて、Python書いてとしていると文法等がこんがらがってしまうのが最近の悩みのひとつです･･･

(ソースコードに汚い部分がありましたらご容赦ください･･･)

ではまた！