こんにちは、広野です。
アプリをつくっていると、ユーザごとのデータ保持が必要になる局面があります。そんなとき、全ユーザの設定データを1つのテーブルでまとめて保持し、かつユーザ単位または設定項目単位で設定データを取り出し易くしたいです。
この度、DynamoDBでそんなユーザ設定テーブルを作ってみたので紹介します。アプリの開発フレームワークは React を使用します。アプリ側でデータをどう扱うか、も本記事のポイントです。
やりたいこと
- アプリ開発フレームワークは React を使用する。
- アプリを使用する全ユーザの設定データを1つのテーブルでまとめて保持したい。
- ユーザの設定データはユーザ単位でまとめて、または設定項目単位で取得できる。
- アプリ内で設定データを取り扱い易くする。
実現方法
AWSを使ったアーキテクチャ的には以下の図のようになります。本記事では Amazon DynamoDB のテーブル設計やデータの扱い方を主旨としますので、Amazon API Gateway や AWS Lambda についての説明は割愛します。
データ設計
Amazon DynamoDB テーブルにどのようにユーザ設定データを持たせ、アプリ側では最終的にどのようなデータになるのかイメージしてみました。複数ユーザの設定項目、設定パラメータが放り込まれている状態です。
Amazon DynamoDB テーブル内のデータ例
[ { "username": "user01", "key": "config-isAbcEnabled", "data": true }, { "username": "user01", "key": "config-nickname", "data": "ニックネーム" }, { "username": "user01", "key": "isLicenseAgreed", "data": true }, { "username": "user02", "key": "config-isAbcEnabled", "data": true }, { "username": "user02", "key": "config-nickname", "data": null }, { "username": "user02", "key": "isLicenseAgreed", "data": false } ]
アプリ内で欲しいデータ例
上記 Amazon DynamoDB のテーブルから、ログインしているユーザのユーザ名、例えばここでは user01 のデータだけを取ってきたときに、以下のようなデータフォーマットにしたいです。
{ "config-isAbcEnabled": true, "config-nickname": "ニックネーム", "isLicenseAgreed": true }
必要なのはログイン中ユーザの設定データだけなので、ユーザ名は必要ありません。設定項目名と、設定パラメータだけ羅列している状態が理想です。このフォーマットに落とせれば、アプリから設定データを取り出し易いです。
実装例
Amazon DynamoDB テーブル
Amazon DynamoDB テーブルは、シンプルです。username 単位、設定項目名 (key) 単位でデータを取得できるよう、以下のキー設定にします。
パーティションキー | ソートキー |
---|---|
username | key |
必要に応じて、その他オプション設定をして頂ければと思います。
Reactアプリのコード
Amazon DynamoDB からユーザ設定データを取得する
いくつかのコンポーネントで分散してユーザ設定データを取得する可能性があり、関数化しています。いくつかパターンを作ったので、以下は一例です。
//ユーザデータ1格納state定義(DynamoDBから取得直後) const [userdata1, setUserdata1] = useState([]); //ユーザデータ取得関数(begins_with条件) const getUserdataBgn = async (username, key, headerdata) => { const res = await axios.post( process.env.REACT_APP_USERDATA_URL + "/GetUserdataBgn", //API Gateway エンドポイントは環境変数化 { user: username, //ここで指定した username のデータを取得する key: key //ここで指定した key を begins_width 条件にしてマッチしたユーザ設定データを取得する }, { headers: headerdata //headerdata にはIDトークンが入り、Cognito Authorizer で使用する } ); return res; }; //ユーザデータ取得 const res = await getUserdataBgn("user01", "config-", headerdata); setUserdata1(res.data.Items);
ここで、例のように username: “user01”, key: “config-” という条件でユーザ設定データを取得すると、以下のデータが抽出され userdata1 の state に格納されます。
[ { "username": "user01", "key": "config-isAbcEnabled", "data": true }, { "username": "user01", "key": "config-nickname", "data": "ニックネーム" } ]
ユーザ設定データを加工する
このままでは期待しているデータフォーマットではないので、アプリ側でデータを加工します。
//ユーザデータ2格納state定義(加工後) const [userdata2, setUserdata2] = useState([]); //Amazon DynamoDBからデータを取得した後、データを整型する let tempdata = { "dummy": false }; //データが空のときにエラーになってしまうので、ダミーデータを1つだけ入れている userdata1.map(function(userdata) { //userdata1を、1行ごとに変数userdataに格納し繰り返し処理をする tempdata[userdata.key] = userdata.data; //変数userdataの中のkey値をキーに、data値をバリューにしてtempdataに追記 }); setUserdata2(tempdata); //最後にtempdataをuserdata2のstateに格納する
この処理をすることで、期待していたデータをアプリ内 userdata2 の state に格納することができました。(ダミーデータは邪魔ですが)
後はアプリ内で、任意の設定データを使った処理をすることになります。
{ "config-isAbcEnabled": true, "config-nickname": "ニックネーム", "dummy": false }
アプリからユーザ設定データを更新するときには、Amazon DynamoDB テーブルの項目通りにデータをputすればOKです。そこは特段工夫する必要はありません。
まとめ
いかがでしたでしょうか?
ユーザ設定データを扱う方法の一例として、みなさまのお役に立てれば幸いです。
私は React アプリ内でデータを加工しましたが、AWS Lambda 関数の中で加工してあげる方がアプリコードが綺麗になりますね。また、もっとスマートな処理が随所にありそうです。
みなさまは是非この記事をあくまでも参考に、改善して実装してもらえたらと思います。