LoginSignup
4
9

More than 3 years have passed since last update.

Laravel+AWS-SDK-PHPによるDynamoDBのデータ取得

Last updated at Posted at 2020-08-06

背景

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);

・結果
image.png

参考

4
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
9