ニフクラ mobile backend(mBaaS)お役立ちブログ

スマホアプリ開発にニフクラ mobile backend(mBaaS)。アプリ開発に役立つ情報をおとどけ!

Monaca × NCMBで位置情報検索アプリを作る(その2:位置情報データのインポート)

f:id:mbaasdevrel:20210706221728j:plain

NCMBにはいくつかの機能がありますが、アプリと親和性の高い機能としてはプッシュ通知と位置情報機能が挙げられます。デバイスから位置情報を取得し、それをマッピングしたり、自分の今いる場所に近い情報を得たりする際にも位置情報検索が利用できます。

今回はMonacaとNCMBで位置情報検索を行うアプリを作成してみます。前回は、データストアのスキーマや画面について解説しました。今回は位置情報データのインポートを解説します。

インポート画面について

f:id:mbaasdevrel:20210706221654j:plain

インポート画面 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;
}

処理の実行

インポートボタンを押すと、取り込まれた駅名がリスト表示されていきます。そして最後にアラートが出て完了です。

f:id:mbaasdevrel:20210706221728j:plain

管理画面での表示

管理画面のデータストアにStationクラスが追加され、その中に駅名が並んでいるのが確認できるはずです。

f:id:mbaasdevrel:20210706221739j:plain

コードについて

今回のコードは以下のリポジトリにて公開しています。ライセンスはMIT Licenseになりますので、自由にご利用ください。

NCMBMania/monaca_map_app: Monacaで位置情報検索を利用したデモアプリです。

まとめ

今回は位置情報オブジェクトを定義し、データストアの中にインポートする処理を紹介しました。次回はMapboxと組み合わせて、データを地図上に表示するまでを実装します。

中津川 篤司

中津川 篤司

NCMBエヴァンジェリスト。プログラマ、エンジニアとしていくつかの企業で働き、28歳のときに独立。 2004年、まだ情報が少なかったオープンソースソフトの技術ブログ「MOONGIFT」を開設し、毎日情報を発信している。2013年に法人化、ビジネスとエンジニアを結ぶDXエージェンシー「DevRel」活動をスタート。