背景
LaravelでDynamoDB使うにあたり、ORMのlaravel-dynamodbなどもあるが、DynamoDBでORM利用するのが少し違和感あった為にSDK使ってやってみた際のメモ(そもそもPHPのWEBフレームワークでやるなという話ではあるが、せっかくSDKが提供されているので一度使ってみようという感じ)
環境
・Windows 10
・HomeStead 9.5
・PHP 7.4
・Laravel 6.0
1.準備
AWS-SDK-PHPのインストール
composer require aws/aws-sdk-php
DynamoDBの環境作成
AWS提供のローカルDynamoDBを利用。Vagrantを使っていたので、Dockerと共存が面倒なことになるのでローカルに直接インストールしました。
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBLocal.html
※GUIツール(結構便利)
https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.html
DynamoDB起動
java -Djava.library.path=C:\localsandbox\DynamoDB\DynamoDBLocal_lib -jar C:\localsandbox\DynamoDB\DynamoDBLocal.jar -port 8001 -sharedDb
※HomesteadのVirtualBoxと初期ポート8000が被るので、8001で起動させる
テスト用テーブルの作成
テーブル名:SensorLog
パーティションキー:device_id
ソートキー:receive_dt
aws dynamodb create-table --table-name SensorLog --attribute-definitions AttributeName=device_id,AttributeType=S AttributeName=receive_dt,AttributeType=N --key-schema AttributeName=device_id,KeyType=HASH AttributeName=receive_dt,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 --endpoint-url http://localhost:8001
※キーのない項目はテーブル作成時に指定できないので、テストデータ作成時に適当に作る。
※テストデータはGUIで適当に作成
.envに情報設定
DYNAMODB_REGION=ap-northeast-1
#↓vagrantのlocalhost:xxxxだとつながらないのでローカルIPを設定
DYNAMODB_LOCAL_ENDPOINT=http://192.168.11.99:8001
DYNAMODB_DEBUG=true
2.データ取得
・パーティションキーで絞ってデータ検索した結果の最新を取得する。
・パーティションキー+ソートキー(範囲指定)による複合条件検索の結果リストを取得する
use Aws\DynamoDb\Exception\DynamoDbException;
use Aws\DynamoDb\Marshaler;
use Aws\Sdk as AwsSdk;
class SensorLog
{
/**
* @var DynamoDbClient
*/
private $client;
/**
* @var Marshaler
*/
private $marshaler;
/**
* DynamoModel constructor.
*/
public function __construct()
{
// ローカルDBであっても"credentials"定義しないとエラーが吐かれるので注意
$sdk = new AwsSdk([
'credentials' => [
'key' => env('DYNAMODB_KEY'),
'secret' => env('DYNAMODB_SECRET'),
],
'endpoint' => env("DYNAMODB_LOCAL_ENDPOINT"),
'region' => env("DYNAMODB_REGION"),
'version' => 'latest'
]);
$this->client = $sdk->createDynamoDb();
$this->marshaler = new Marshaler();
}
/**
* パーティションキー指定による最新データを取得する
*/
public function getFirst($id)
{
$tableName = 'SensorLog';
// 検索条件設定:device_idを検索条件にする
$key_value = $id;
$jsonStr = '{'.'":device_id":'.'"'.$key_value.'"'.'}';
$eav = $this->marshaler->marshalJson($jsonStr);
// Limit:1 取得件数を1件に制限
// ScanIndexForward:false ソートキー(receive_dt)を降順指定
$params = [
'TableName' => $tableName,
'KeyConditionExpression' => '#id = :device_id',
'ExpressionAttributeNames'=> [ '#id' => 'device_id' ],
'Limit' => 1,
'ScanIndexForward' => false,
'ExpressionAttributeValues'=> $eav,
];
try {
$result = $this->client->query($params);
$data = array();
foreach ($result['Items'] as $recdData) {
$data[] = $this->marshaler->unmarshalItem($recdData);
}
return $data;
} catch (DynamoDbException $e) {
throw $e;
}
}
/**
* パーティションキー+対象日付のデータリストを取得する
*/
public function getDataByDateTime(int $id, string $dt)
{
$tableName = 'SensorLog';
// 対象日付の最小時間と最大時間を設定する
// receive_dt:YYYYMMDDHHMMSSの値は数値型で格納されている
$from_dt = $dt."000000";
$to_dt = $dt."235959";
// バインド変数を設定(device_id,from_dt,to_dt)
$key_value = $id;
$jsonStr = '{' . '":device_id":' . '"' .$key_value.'",":from_dt":'.$from_dt.',":to_dt":'.$to_dt.'}';
$eav = $this->marshaler->marshalJson($jsonStr);
// device_idとreceive_dtによる範囲検索を行う
// ScanIndexForward:false ソートキー(receive_dt)を降順指定
$params = [
'TableName' => $tableName,
'KeyConditionExpression' => '#id = :device_id and receive_dt between :from_dt and :to_dt',
'ExpressionAttributeNames'=> [ '#id' => 'device_id' ],
'ScanIndexForward' => false,
'ExpressionAttributeValues'=> $eav,
];
try {
$result = $this->client->query($params);
$data = array();
foreach ($result['Items'] as $recdData) {
$data[] = $this->marshaler->unmarshalItem($recdData);
}
return $data;
} catch (DynamoDbException $e) {
throw $e;
}
}
}
呼び出し
・コントローラーで呼び出し
//1.指定IDの最新データを1件取得
$sensorLog = $sensor->getFirst($id);
//2.2020-08-06のデータを検索して結果リストを取得
$sensorLogList = $sensor->getDataByDateTime($id, "20200806");
dump($sensorLogList);
参考