チュートリアル: FTXUI を使用した C++ 用 Atlas Device Sync
項目一覧
完了までの推定時間: 30分(C++ の経験により異なります)
Atlas Device SDK for C++ を使用すると、携帯電話、テーブル、ウェアラブル、または IoT デバイス全体でデータを保存および同期できます。 This tutorial is based on the C++ Template App, named cpp.todo.flex
, which illustrates the creation of a to-do list terminal GUI application built with FTXUI. このアプリケーションを使用すると、ユーザーは次のことが可能になります。
メールを新しいユーザー アカウントとして登録します。
メールとパスワードを使用してアカウントにサインインします(その後サインアウトします)。
自分のタスクを表示、作成、変更、削除します。
ユーザーが所有者でない場合でも、すべてのタスクを表示します。
また、テンプレートアプリには、デバイスがオフラインモードになっていることをシミュレートするトグルが用意されています。 このトグルを使用すると、シミュレーターで Device Sync 機能をすばやくテストして、インターネットに接続していないユーザーをエミュレートできます。 ただし、本番アプリケーションではこのトグルを削除する可能性が高いでしょう。
このチュートリアルでは、テンプレート アプリを対象に構築を行います。 既存のItem
モデルに新しいpriority
フィールドを追加し、 Flexible Sync サブスクライブを更新して、優先順位の範囲内のアイテムのみを表示します。
学習目的
このチュートリアルでは、テンプレート アプリを独自のニーズに合わせて調整する方法について説明します。 テンプレート アプリの現在の構造を考慮すると、必ずしもこの変更を行う必要はありません。
このチュートリアルでは、次の方法を学習します。
重大じゃない変更で C++ オブジェクト モデルを更新します。
Device Sync サブスクライブを更新します。
同期されるデータを変更するには、サーバー上の Device Sync 構成にクエリ可能なフィールドを追加します。
Tip
ガイド付きチュートリアルに従うのではなく、独自のアプリケーションを使い始める場合は、 C++ クイック スタートを確認します。 コピー可能なコード サンプルと、Atlas App Services バックエンドを設定するために必要な重要な情報が含まれています。
前提条件
必要なソフトウェアがインストールされていることを確認してください。 C++ テンプレート アプリでは、次のことを前提としています。
CMax バージョン3 。25 以上
C++ 17以上
このチュートリアルは、テンプレート アプリから始めます。 テンプレート アプリを作成するには、 Atlas アカウント、 API キー、 App Services CLI が必要です。
Atlas アカウントの作成の詳細については、「 Atlas の使用開始」ドキュメントを参照してください。 このチュートリアルでは、無料階層クラスターを持つ Atlas アカウントが必要です。
ログインする MongoDB Cloud アカウントの Atlas API キーも必要です。 App Services CLI を使用してテンプレート アプリを作成するには、プロジェクト オーナーである必要があります。
App Services CLI のインストールについて詳しくは、「 App Services CLI のインストール」を参照してください。 インストール後、Atlas プロジェクトの API キーを使用して「 login 」コマンドを実行します。
テンプレートを使用して開始
このチュートリアルは、 cpp.todo.flex
という名前の C++ Sync テンプレート アプリを基本にして作成されており、 デフォルトのアプリから始めて、新しい機能について説明しています。
テンプレート アプリの詳細については、「テンプレート アプリ 」を参照してください。
Atlas アカウントがまだない場合は、テンプレート アプリを配置するためにサインアップしてください。
「App Services App」ガイドに記載されている手順に従い、 Create App from Templateを選択します。Real-time Sync テンプレートを選択します。これにより、Device Sync テンプレート App Services App クライアントの 1 つで使用するために事前構成された App Services App が作成されます。
テンプレート アプリを作成すると、UI に Get the Front-end Code for your Template というラベルの付いたモーダルが表示されます。このモーダルには、テンプレート アプリのクライアントコードを .zip
ファイルとしてダウンロードする方法や、App Services CLI を使用してクライアントを取得する方法が表示されます。
C++ テンプレート アプリはまだ、App Services UI ではダウンロードできません。 CLIを使用するか、 Githubからリポジトリをクローンしてクライアントコードを取得します。
appservices apps createコマンドでバックエンドを設定し、C++ テンプレート アプリを作成してこのチュートリアルのベースとして使用します。
ターミナル ウィンドウで次のコマンドを実行して、「Myチュートリアル App」という名前のアプリを作成し、環境が「開発」(本番環境やQAではなく)に設定されているUS-VA
リージョンに配置されます。
appservices app create \ --name MyTutorialApp \ --template cpp.todo.flex \ --deployment-model global \ --environment development
このコマンドは、 --name
フラグの値と同じ名前で現在のパスに新しいディレクトリを作成します。
Device Sync クライアントコードを含む Github リポジトリをフォークしてクローンできます。 C++ クライアント コードは https://github.com/mongodb/template-app-cpp-todo で入手できます。
このプロセスを使用してクライアントのコードを取得する場合は、クライアントで使用するテンプレート アプリを作成する必要があります。 「テンプレート アプリの作成」 の手順に従って、Atlas App Services UI、App Services CLI、または管理 API を使用して Device Sync テンプレート アプリを作成します。
テンプレート アプリを調べる
アプリをビルドする
アプリをビルドするディレクトリを作成します。 便宜上、テンプレート アプリにパッケージ化された
.gitignore
は、クライアント ディレクトリ内のbuild
ディレクトリを無視します。 ビルド ディレクトリに移動します。mkdir build && cd build CSpec を使用して Search ファイルを作成します。 クライアント ディレクトリ内の
build
ディレクトリから構築しているとします。cmake ../ CSpec を使用してアプリ実行可能ファイルを構築します。 これには、依存関係をインストールし実行可能ファイルをコンパイルする際にいくつかの時間がかかります。
cmake --build .
アプリ構造の探索
CSpec が実行可能ファイルを構築している間にプロジェクトがどのように構成されているかを調べます。
このチュートリアルではこれらのファイルを直接操作することはありませんが、C++ SDK の使用を示すコードが含まれています。
ファイル | 目的 |
---|---|
controllers/app_controller.cpp |
アプリ構成をカスタマイズする方法の詳細については、「 Atlas App Services バックエンドへの接続 」を参照してください。 このコードでは、 |
managers/auth_manager.cpp | メール/パスワード ユーザーを登録し、ユーザーをログインまたはログアウトさせ、認証エラーが発生したときにエラー メッセージを表示するロジック。 |
このチュートリアルでは、次のファイルを操作します。
ファイル | 目的 |
---|---|
state/item.hpp | データベースに保存する Item オブジェクトを定義します。 |
state/home_controller_state.hpp | ホーム ビューでアプリの状態を管理します。 |
controllers/home_controller.hpp | Home ビュー コントローラーの重要な定義が含まれています。 |
controllers/home_controller.cpp | ホーム ビューを実装します。 これは、ログインしたユーザーがアプリを操作できるビューです。 |
managers/database_manager.hpp | Device Sync とデータベース操作のための重要な定義が含まれています。 |
managers/database_manager.cpp | アイテムの作成、Device Sync クエリ サブスクリプションの変更、Sync エラーの処理など、一部の Device Sync およびデータベース操作を実装します。 |
アプリを実行する
コードを変更しなくても、ターミナルでアプリを実行できるはずです。 アプリケーションを実行する際に、 atlasConfig.json
へのパスを引数として渡します。
./sync_todo /path-to-file/atlasConfig.json
アプリを実行し、新しいユーザーアカウントを登録し、新しいアイテムを Todo リストに追加します。
Tip
必要に応じて、ターミナル ウィンドウを展開します。
ホーム画面の上部には、一連のボタンと、完了したタスクを非表示にするトグルが含まれています。 ターミナル ウィンドウが小さすぎると、ボタンのテキスト ラベルは表示されません。 ラベルを表示するには、ターミナル ウィンドウを大きくし、FTXUI がより大きなウィンドウに収まるようにコンテンツを再レンダリングします。
バックエンドの確認
Atlas App Servicesにログインします。 Data Servicesタブで、 Browse Collectionsをクリックします。 データベースのリストで、 todoデータベース、 Itemコレクションを検索して展開します。 このコレクションで作成したドキュメントが表示されます。
アプリケーションを変更する
新しいプロパティの追加
モデルへのプロパティの追加
すべて期待どおりに動作していることが確認できたため、変更を追加できます。 このチュートリアルでは、各Item
にpriority
プロパティを追加し、アイテムを優先順位でフィルタリングできます。
本番アプリでは、可能な値を制限するためにPriorityLevel
列挙型を追加できます。 このチュートリアルでは、数値プロパティを使用して UI フレームワークの操作を簡素化します。
これを行うには、次の手順に従います。
希望する IDE でクライアント コードを開きます。
state/
ディレクトリで、item.hpp
ファイルを追加します。次のプロパティを
Item
構造体に追加します。int64_t priority; 新しい
priority
プロパティをREALM_SCHEMA()
に追加する。REALM_SCHEMA(Item, _id, isComplete, summary, owner_id, priority) Item
モデルは次のようになります。namespace realm { struct Item { realm::primary_key<realm::object_id> _id{realm::object_id::generate()}; bool isComplete; std::string summary; std::string owner_id; int64_t priority; }; REALM_SCHEMA(Item, _id, isComplete, summary, owner_id, priority) } // namespace realm
優先順位を設定するために UI に要素を追加する
state
ディレクトリで、home_controller_state.hpp
にGoします。 既存のnewTaskIsComplete
プロパティの下に新しいint
プロパティを追加します。 次に、このプロパティのデフォルトの int 値を保存するためにstatic const int
を追加します。HomeControllerState
構造は次のようになります。struct HomeControllerState { static const int DEFAULT_TASK_PRIORITY = 3; // Used for creating a new task. std::string newTaskSummary; bool newTaskIsComplete{false}; int newTaskPriority{DEFAULT_TASK_PRIORITY}; ...more code here... }; controllers
ディレクトリで、home_controller.hpp
にGoします。 このコントローラーは、アプリのメインビューをレンダリングします。string ライブラリとベクトル ライブラリをインポートします。
新しい優先順位 UI 要素のstringラベルの配列を作成します。
std::vector<std::string> priorityLevelLabels = { "Severe", "High", "Medium", "Low" }; まだ
controllers
ディレクトリにある場合は、home_controller.cpp
にGoします。 ここで、ユーザーがアイテムの優先順位を設定できるように UI 要素を追加します。 FTXUI は、この機能に使用できる 2 つの UI 要素を提供しています(Radiobox
またはDropdown
。 このチュートリアルではDropdown
を使用しますが、UI がドロップダウンをレンダリングするためにリフローする方法が望ましくない場合は、Radiobox
を使用する方が適しているかもしれません。この新しい UI 要素の入力を
auto newTaskCompletionStatus
行の後に追加します。auto newTaskPriorityDropdown = ftxui::Dropdown( &priorityLevelLabels, &_homeControllerState.newTaskPriority ); auto saveButton
関数閉じで、タスク優先順位の選択を_dbManager.addNew()
関数呼び出しに渡します。_dbManager.addNew( _homeControllerState.newTaskIsComplete, _homeControllerState.newTaskSummary, _homeControllerState.newTaskPriority); 次に、優先順位の選択をデフォルト値にリセットする行を追加します。
_homeControllerState.newTaskPriority = HomeControllerState::DEFAULT_TASK_PRIORITY; アイテム行コンテナ内のインタラクティブ要素の配置を設定する
auto newTaskLayout
にドロップダウン セレクターを追加します。auto newTaskLayout = ftxui::Container::Horizontal( {inputNewTaskSummary, newTaskCompletionStatus, newTaskPriorityDropdown, saveButton}); コードのこのセクションは次のようになります。
auto newTaskCompletionStatus = ftxui::Checkbox("Complete", &_homeControllerState.newTaskIsComplete); auto newTaskPriorityDropdown = ftxui::Dropdown( &priorityLevelLabels, &_homeControllerState.newTaskPriority); auto saveButton = ftxui::Button("Save", [this] { _dbManager.addNew( _homeControllerState.newTaskIsComplete, _homeControllerState.newTaskSummary, _homeControllerState.newTaskPriority); _homeControllerState.newTaskSummary = ""; _homeControllerState.newTaskIsComplete = false; _homeControllerState.newTaskPriority = HomeControllerState::DEFAULT_TASK_PRIORITY; }); auto newTaskLayout = ftxui::Container::Horizontal( {inputNewTaskSummary, newTaskCompletionStatus, newTaskPriorityDropdown, saveButton}); 最後に、
home_controller.cpp
ファイルのさらに下にあるセカンダリの UI 要素をauto itemListRenderer
に追加します。inputNewTaskSummary->Render() | ftxui::flex, newTaskCompletionStatus->Render() | ftxui::center, newTaskPriorityDropdown->Render(), saveButton->Render(), これにより、UI の 保存 ボタンの直前に新しい要素がレンダリングされます。
新しいプロパティをデータベースに保存する
managers
ディレクトリで、database_manager.hpp
にGoします。addNew()
関数のシグネチャを更新して、home_controller.cpp
から渡すint newItemPriority
を含めます。void addNew( bool newItemIsComplete, std::string newItemSummary, int newItemPriority); 次に
database_manager.cpp
にGoし、addNew()
の実装を更新します。 関数の引数にint newItemProperty
を追加します。void DatabaseManager::addNew( bool newItemIsComplete, std::string newItemSummary, int newItemPriority) { ...implementation... } Item
をデータベースに保存するときに、priority
プロパティの値を設定するための関数に新しい行を追加します。.priority = newItemPriority これで、
addNew()
の実装は次のようになります。void DatabaseManager::addNew(bool newItemIsComplete, std::string newItemSummary, int newItemPriority) { auto item = realm::Item { .isComplete = newItemIsComplete, .summary = std::move(newItemSummary), .owner_id = _userId, .priority = newItemPriority }; _database->write([&]{ _database->add(std::move(item)); }); }
およびテストの実行
この時点で、アプリケーションを再度ビルドして実行します。 ビルド ディレクトリで、行った変更を反映して実行可能ファイルを再ビルドします。
cmake --build .
そして、アプリを実行します。
./sync_todo /path-to-file/atlasConfig.json
このチュートリアルの前半で作成したアカウントを使用してログインします。 過去に作成した 1 つのアイテムが表示されます。新しいアイテムを追加すると、優先順位を設定できるようになります。優先順位を High
にし、アイテムを保存します。
ブラウザで Atlas データページに切り替え、 Item
コレクションを更新します。 これでpriority
フィールドが追加され、 1に設定された新しいアイテムが表示されます。 既存のアイテムにはpriority
フィールドはありません。
注意
同期が中断されなかった理由
SDK クライアント オブジェクトにプロパティを追加しても重大な変更ではないため、クライアントをリセットする必要はありません。 テンプレート アプリでは開発モードが有効になっているため、クライアント オブジェクトへの変更はサーバー側のスキーマに自動的に反映されます。 詳しくは、「開発モードとデータモデルの更新 」を参照してください。
サブスクリプションを変更する
managers
ディレクトリのdatabase_manager.cpp
ファイルでは、ユーザーのデバイスとアカウントで同期するドキュメントを定義する Flexible Sync サブスクリプションが作成されます。 デフォルトでは、すべてのアイテムをサブスクライブします。 他のユーザーが作成したアイテムは表示できますが、サーバー側のルールによりそれらに書き込むことはできません。 このロジックは、初期サブスクリプションを作成するブロックに記載されています。 アプリを開くときにサブスクライブがない場合は、すべてのItem
オブジェクトのサブスクライブを追加します。
_database->subscriptions().update([this](realm::mutable_sync_subscription_set& subs) { // By default, we show all items. if (!subs.find(_allItemSubscriptionName)) { subs.add<realm::Item>(_allItemSubscriptionName); } }).get();
toggleSubscriptions()
関数では、現在のサブスクライブ状態に応じてサブスクリプションを切り替えます。 UI では、ユーザーはすべてのアイテムを表示するか、自分のアイテムのみを表示するかを切り替えることができます。 この関数内で、 _myItemSubscriptionName
ロジックを見つけます。 このサブスクリプション名のサブスクライブがまだ存在しない場合、アプリはowner_id
プロパティが認証されたユーザーの ID と一致するすべてのドキュメントにサブスクライブを追加します。
このチュートリアルでは、それを維持し、優先順位が「高」または「重要」とマークされたアイテムのみを同期します。
そのため、 priority
プロパティにint64_t
を使用し、UI の優先度レベルを最も重要なものから最も重要でないものの順にラベル付けしました。 最高優先順位(重大)の値は0で、最低優先順位(低)の値は3です。 数値と優先順位プロパティを直接比較できます。
サブスクライブを更新する
サブスクリプションを変更するには、managers
ディレクトリにGoし、database_manager.cpp
ファイルを開きます。 優先順位が1以下のドキュメントを含むようにクエリ ステートメントを更新します。 これには、優先順位が「重要」( 0 )または「高」( 1 )のアイテムのみを含める必要があります。
if (!subs.find(_myItemSubscriptionName)) { subs.add<realm::Item>( _myItemSubscriptionName, [&](auto &item){ return item.owner_id == _userId && item.priority <= 1; } ); }
およびテストの実行
アプリケーションを再度実行します。 このチュートリアルの前半で作成したアカウントを使用してログインします。 Subscription
ボックスで、 Switch to
Mine
ボタンを押します。 SDK がドキュメントコレクションを再同期する最初の瞬間、作成した優先順位の高い新しいアイテムのみが表示されます。 バックグラウンドで同期された新しい項目で UI を再レンダリングするには、マウスを移動するか、矢印キーを使用する必要がある場合があります。
最初に作成したアイテム ドキュメントは、 priority
フィールドがないため、デバイスに表示されません。 このアイテムをデバイスと同期する場合は、Atlas UI でドキュメントを編集し、 priority
フィールドに値を追加できます。
Tip
開発者モードが有効になっている場合にサブスクリプションを変更する
このチュートリアルでは、サブスクリプションを変更し、優先順位フィールドを初めてクエリすると、フィールドは Device Sync Collection Queryable Fieldsに自動的に追加されます。 これは、テンプレート アプリで開発モードがデフォルトで有効になっているために発生します。 開発モードが有効になっていない場合、クライアント側の同期クエリで使用するには、フィールドをクエリ可能なフィールドとして手動で追加する必要があります。
詳細については、「クエリ可能なフィールド 」を参照してください。
機能をさらにテストしたい場合は、さまざまな優先順位のアイテムを作成できます。 優先順位の低い新しいアイテムがアイテム リストに一時的に表示され、その後消えます。 同期エラー ハンドラーは、この動作を説明するメッセージを提供します。
A sync error occurred. Message: "Client attempted a write that is not allowed; it has been reverted"
このシナリオでは、SDK はアイテムをローカルに作成し、バックエンドと同期した後、サブスクライブ ルールを満たしていないため書き込みを元に戻します。
注意
既知の UI の問題
エラー モーダルが表示されており、エラー モーダルを閉じる前にターミナル内のアイテム リストの上にマウスを移動すると、UI のレンダリングが中断されます。 これは、FTXUI ライブラリの制限に関連しています。 この問題が発生した場合は、 ctrl + c
を使用してアプリを終了し、再実行してください。 この問題を回避するには、マウスを移動する前に Enter キーを使用してエラー モーダルのDismiss
ボタンを押します。
まとめ
既存の SDK オブジェクトにプロパティを追加することは重大じゃない変更であり、 開発モード によりスキーマの変更がサーバー側に反映されるようになります。
次のステップ
C++ SDKのドキュメントをお読みください。
MongoDB Communityに参加して、他の MongoDB 開発者や技術専門家から学びます。
エンジニアリング プロジェクトと専門家が提供するサンプルプロジェクトを探索します。
注意
フィードバックの共有
ではどのようにGoしましたか。 ページ右下にあるRate this pageウィジェットを使用して、有効性を評価します。 またはGithub リポジトリ に問題を報告する 問題が発生した場合は、。