はじめに
皆さん。こんにちは! DreamHanksのエルムです。
今回はデータをクラウドに同期する簡単な方法について説明していきます。
前回の記事はAmplify & GraphQLでのデータモデル設計です。
アプリケーションが完成したら、プロジェクトからバックエンドをプロビジョニングすることで、 クラウドとの同期を開始できます。DataStoreは、データプロトコルとしてGraphQLを使用して、リモートのバックエンドに接続し、ローカルに保存されたすべてのデータを自動的に同期することができます。
ベストプラクティス:最初はクラウド同期を有効にせずに開発することをお勧めします。そうすれば、プロビジョニングされたバックエンドを更新することなく、アプリケーションの形に合わせてスキーマを変更することができます。データスキーマの安定性に満足したら、以下のようにクラウド同期を設定すると、ローカルに保存されたデータが自動的にクラウドに同期されます。
クラウドシンクを設定する方法 (Setup cloud sync)
オフラインとオンラインのデータを同期させるのは難しいことです。DataStoreの目標は、アプリケーションコードからその負担を取り除き、開発者がアプリケーションロジックに集中している間に、ローカルとリモート間のすべてのデータの一貫性と調整を舞台裏で処理することです。ここまでは、オフラインで動作し、データ永続化フレームワークに期待されるすべての機能を備えたローカルデータストアをセットアップすることに重点を置いていました。
次のステップは、ローカルに保存されたデータがAWS AppSyncを利用したクラウドのバックエンドと同期されるようにすることです。
バックエンドをクラウドにプッシュする方法
バックエンドのステータスを確認し、クラウドですでにプロビジョニングされているかどうかを確認します:
1 |
amplify status |
このような表が表示されるはずです:
1 2 3 |
| Category | Resource name | Operation | Provider plugin | | -------- | ----------------- | --------- | ----------------- | | Api | amplifyDatasource | No Change | awscloudformation | |
トラブルシューティング:もしamplify statusで *”You are not working inside a valid Amplify project “* というエラーが出た場合は、次のステップの前にamplify initを実行してください。
OperationがCreateまたはUpdateの場合は、バックエンドをクラウドにプッシュする必要があります。
1 |
amplify push |
AWSのクレデンシャルが必要です。この時、AWSのアカウントが必要です。これまでにamplify configureを実行したことがない場合は、そのように実行し、手順に従ってamplifyをAWSアカウントで設定します。
詳細はConfigure the Amplify CLIガイドに記載されています。
既存のバックエンド (Existing backend)
DataStoreは、他のプロジェクトからデプロイされた既存のAWS AppSyncバックエンドに、元々作成されたプラットフォームに関係なく接続することができます。このようなワークフローでは、ターミナルからamplify pullコマンドを実行し、その後モデルを生成することで、CLIを直接操作することが最善です。
分散データ (Distributed data)
分散されたデータを扱う際には、ローカルとリモートのシステムの状態に気を配ることが重要です。DataStoreは、お客様のためにできるだけシンプルにしたいと考えていますが、いくつかのシナリオでは検討が必要です。
例えば、データの更新や削除を行う際には、ローカルデータの状態がバックエンドと同期していない可能性があることを考慮しなければなりません。このシナリオは、条件をどのように実施するかに影響を与えます。
述語による更新と削除
このような場合、save()とdelete()の両APIは、オプションの述語をサポートしています。この述語は、バックエンドに送信され、リモートの状態に対して実行されます。
1 2 3 4 5 6 7 8 |
await DataStore.save( new Post({ title: "私の最初のPost", rating: 10, status: PostStatus.DRAFT }), (p) => p.title('beginsWith', '[Amplify]') ); |
if/else構文を用いた従来のローカルな条件チェックと、前述のAPIの述語との間には、以下の例に見られるような違いがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// ローカルステートに対してのみテスト if (post.title.startsWith("[Amplify]")) { await DataStore.save(post); } // リモートバックエンドのデータが基準を満たしている場合にのみアップデートを適用する await DataStore.save( new Post({ title: "私の最初のPost", rating: 10, status: PostStatus.DRAFT }), p => p.title('beginsWith', '[Amplify]') ); |
コンフリクトの検出と解決: 複数の場所で同時にデータを更新する場合、コンフリクトが発生する可能性があります。ほとんどの場合、デフォルトのAuto-mergeアルゴリズムでコンフリクトを解決できるはずです。しかし、アルゴリズムを解決できないシナリオもあります。このような場合には、より高度なオプションが用意されていますので、次のセクションで詳しく説明します。
ローカルデータの消去 (Clear local data)
Amplify.DataStore.clear()は、必要に応じて全てのローカルデータを消去する方法を提供します。これは破壊的な操作ですが、リモートデータはそのまま残ります。次の同期が行われると、データは再びローカルストレージに取り込まれ、ローカルデータが再構築されます。
clear()の一般的な用途としては、同じデバイスを共有する異なるユーザーの管理や、開発時のユーティリティーとしての利用が挙げられます。
注意:複数のユーザーが同じデバイスを共有していて、スキーマにユーザー固有のデータが定義されている場合、ユーザーを切り替える際には必ずAmplify.DataStore.clear()を呼び出すようにしてください。
1 2 3 4 5 |
Hub.listen('auth', async (data) => { if (data.payload.event === 'signOut') { await DataStore.clear(); } }); |
これは、シンプルかつ効果的な例です。しかし、実際のシナリオでは、同じユーザーが何度もサインインしてデータベースがクリアされるのを避けるために、異なるユーザーがサインインしたときにのみclear()を呼び出したいと思うかもしれません。
データの一部を選択的に同期する方法 (Selectively syncing a subset of your data)
デフォルトでは、DataStoreはクラウドデータソースのコンテンツ全体をローカルデバイスにダウンロードします。
選択的な同期を利用して、データのサブセットのみを永続化することができます。
選択的同期は、ベースとデルタの同期クエリ、および受信サブスクリプションに述語を適用することで機能します:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { DataStore, syncExpression } from 'aws-amplify'; import { Post, Comment } from './models'; DataStore.configure({ syncExpressions: [ syncExpression(Post, () => { return post => post.rating('gt', 5); }), syncExpression(Comment, () => { return comment => comment.status('eq', 'active'); }), ] }); |
DataStoreが同期を開始すると、レーティングが5以上の投稿とステータスが ===「active」のコメントのみがユーザーのローカルストアに同期されます。
開発者は、モデルごとに1つのsyncExpressionのみを指定する必要があります。同一モデルに対するそれ以降の表現は無視されます。
実行時に式を再評価する場合
同期式は、DataStoreが起動するたびに評価されます。式を再評価させるためには、DataStore.clear()またはDataStore.stop()を実行した後、DataStore.start()を実行します。
次のような式があり、実行時に適用されるフィルターを変更したい場合は、次のようにします:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let rating = 5; DataStore.configure({ syncExpressions: [ syncExpression(Post, () => { return post => post.rating('gt', rating)); }) ] }); async function changeSync() { rating = 1; await DataStore.stop(); await DataStore.start(); } |
DataStore.start()を呼び出す(またはDataStoreの操作(query、save、delete、observeなど)を実行する)と、DataStoreはsyncExpressionsを再評価します。
上記のケースでは、述語に1という値が含まれているので、レーティングが1を超えるすべてのPostが同期されます。
留意してください:DataStore.stop()は、ローカルストアの既存のコンテンツを保持します。
DataStore.clear()を実行して、ローカルに保存されているコンテンツをクリアします。
限定的なフィルタを適用する場合は、DataStore.clear()を実行して、まずローカルレコードをクリアします。
1 2 3 4 5 |
async function changeSync() { rating = 8; await DataStore.clear(); await DataStore.start(); } |
これにより、ローカルストアのコンテンツが消去され、同期式が再評価され、同期クエリに指定されたすべての述語が適用されて、クラウドからデータが再同期されます。
また、同期式がPredicates.ALLを返すようにすると、そのモデルに対するフィルタリングを取り除くことができます。これにより、デフォルトの同期動作と同じ効果が得られます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let rating = null; DataStore.configure({ syncExpressions: [ syncExpression(Post, () => { if (rating) { return post => post.rating('gt', rating)); } return Predicates.ALL; }) ] }); |
DataStore.configure()は、ファイルのルートで一度だけ呼び出す必要があります。
非同期式 (Async expressions)
syncExpressionにはPromiseを渡すことができます:
1 2 3 4 5 6 7 8 |
DataStore.configure({ syncExpressions: [ syncExpression(Post, async () => { const ratingValue = await getRatingValue(); return post => post.rating('gt', ratingValue); }) ] }); |
DataStoreは、Promiseが解決するのを待ってから、式をsyncに適用します。非同期式は、同期式と同様に、実行時に再評価することもできます(前のセクションを参照)。
ショートハンド(Shorthand)
syncExpressionにロジックを追加する必要がない場合は、次のようなショートハンドを使用して、述語を直接返すことができます。
1 2 3 4 5 |
DataStore.configure({ syncExpressions: [ syncExpression(Post, post => post.rating('gt', 5)) ] }); |
終わりに
今回の記事は以上になります。
次回は [第15回] 認証ルールの設定を学びましょう。
ご覧いただきありがとうございます。
コメント