NCMBにはいくつかの機能がありますが、アプリと親和性の高い機能としてはプッシュ通知と位置情報機能が挙げられます。デバイスから位置情報を取得し、それをマッピングしたり、自分の今いる場所に近い情報を得たりする際にも位置情報検索が利用できます。
今回はMonacaとNCMBで位置情報検索を行うアプリを作成してみます。前回は、データストアのスキーマや画面について解説しました。今回は位置情報データのインポートを解説します。
インポート画面について
インポート画面 pages/import.html
は設定タブをタップした際に表示される画面です。インポートを実行するボタンと、ログを表示するリストがあります。
<template> <div class="page"> <div class="navbar"> <div class="navbar-bg"></div> <div class="navbar-inner sliding"> <div class="title">インポート</div> </div> </div> <div class="page-content"> <div class="block"> <div class="row"> <button class="button col" @click=${execImport}>インポート実行</button> </div> </div> <ul id="log"> </ul> </div> </div> </template>
NCMBの初期化
NCMBのJavaScript SDKは js/app.js
にて初期化しておきます。
const applicationKey = 'YOUR_APPLICATION_KEY'; const clientKey = 'YOUR_CLIENT_KEY'; const ncmb = new NCMB(applicationKey, clientKey);
インポートの実行
インポートはボタンをタップした際に呼ばれる execImport
で実行されます。
// インポートの実行 const execImport = async () => { }
まず最初に既存のデータを削除します。これは複数回、何度でもインポート可能とするためです。Stationクラスはデータ登録時にも利用するので関数外のスコープで定義しています。
// 駅クラス(DBでいうテーブル相当) const Station = ncmb.DataStore('Station'); // 既存データを削除する処理 const cleanUp = async () => { // 既存データを検索 const stations = await Station .limit(100) .fetchAll(); // 検索結果をすべて削除 await Promise.all(stations.map(s => s.delete())); } // インポートの実行 const execImport = async () => { // 既存データの削除 cleanUp(); // 省略 }
削除処理はデータを1件ずつ削除する形になります。この削除処理(deleteメソッド)はPromiseを返しますので、map関数で配列化し、まとめてPromise.allで処理結果を待っています。たとえばこれをfor文の中でawaitを使う方式にすると、処理が直列になるので時間が大幅にかかってしまうでしょう。
// 良くない例 for (const s of stations) { await s.delete(); }
既存データを削除したら、山手線の各駅に関する情報が入ったJSONファイルを読み込みます。
// 駅情報のJSONを取得 const res = await fetch('./assets/json/yamanote.json'); const stations = await res.json();
yamanote.jsonの内容は次のようになっています。
[ { "name": "東京", "latitude": "35.681382", "longitude": "139.76608399999998" }, { "name": "有楽町", "latitude": "35.675069", "longitude": "139.763328" }, : ]
このJSONファイルを順番に取り込んでいきます。
// JSONの内容をNCMBに反映する for (const params of stations) { // この中で処理 }
まずStationクラスのインスタンス(DBでいう行相当)を作成します。
// 駅クラスのインスタンス(DBでいう行相当)を用意 const s = new Station;
次に位置情報オブジェクトを作成します。前が緯度、後が経度を引数とします。
// 位置情報オブジェクトを作成 const geo = new ncmb.GeoPoint(parseFloat(params.latitude), parseFloat(params.longitude));
後は駅名と位置情報をセットして保存します。
// 位置情報オブジェクトと駅名をセットして保存 await s .set('name', params.name) .set('geo', geo) .save();
保存が終わったらログを出力しています。今回はログを出力したいので、保存処理を await にしています。本来はループ処理の中で使うべきではないでしょう。
// ログに書き出し $('#log').append(` <li>${s.get('name')}を追加しました</li> `);
これで完成です。import.html の中のJavaScriptは次のようになります。
export default async function (props, {$f7, $f7router, $on, $onBeforeMount, $onMounted, $onBeforeUnmount, $onUnmounted }) { // 駅クラス(DBでいうテーブル相当) const Station = ncmb.DataStore('Station'); // 既存データを削除する処理 const cleanUp = async () => { // 既存データを検索 const stations = await Station .limit(100) .fetchAll(); // 検索結果をすべて削除 await Promise.all(stations.map(s => s.delete())); } // インポートの実行 const execImport = async () => { // 既存データの削除 cleanUp(); // 駅情報のJSONを取得 const res = await fetch('./assets/json/yamanote.json'); const stations = await res.json(); // JSONの内容をNCMBに反映する for (const params of stations) { // 駅クラスのインスタンス(DBでいう行相当)を用意 const s = new Station; // 位置情報オブジェクトを作成 const geo = new ncmb.GeoPoint(parseFloat(params.latitude), parseFloat(params.longitude)); // 位置情報オブジェクトと駅名をセットして保存 await s .set('name', params.name) .set('geo', geo) .save(); // ログに書き出し $('#log').append(` <li>${s.get('name')}を追加しました</li> `); } $f7.dialog.alert('インポート完了しました'); } return $render; }
処理の実行
インポートボタンを押すと、取り込まれた駅名がリスト表示されていきます。そして最後にアラートが出て完了です。
管理画面での表示
管理画面のデータストアにStationクラスが追加され、その中に駅名が並んでいるのが確認できるはずです。
コードについて
今回のコードは以下のリポジトリにて公開しています。ライセンスはMIT Licenseになりますので、自由にご利用ください。
NCMBMania/monaca_map_app: Monacaで位置情報検索を利用したデモアプリです。
まとめ
今回は位置情報オブジェクトを定義し、データストアの中にインポートする処理を紹介しました。次回はMapboxと組み合わせて、データを地図上に表示するまでを実装します。