SQLiteプラグインを使うと、Monacaアプリにローカルに保存される簡易的なデータベースを追加できます。今回はMonacaのテンプレートとして提供されているTodoアプリにデータベース機能を追加してみたいと思います。

SQLiteプラグインについて

今回はlitehelpers/Cordova-sqlite-storage: A Cordova/PhoneGap plugin to open and use sqlite databases on Android, iOS and Windows with HTML5/Web SQL APIを利用しました。Android、iOS両方に対応しています。

インストールはMonacaのCordovaプラグインの管理にて cordova-sqlite-storage を指定します。

アプリ起動時の処理

アプリ起動時には次のような手順で処理を実行します。

  1. プラグインのテスト
  2. データベースを開く
  3. テーブル作成(テーブルがなければ)
  4. 既存データの取り出し

1. プラグインのテスト

まずはプラグインが実行可能かどうかのテストを行います。

document.addEventListener('deviceready', function() {
  // プラグインのテスト
  sqlitePlugin.selfTest(function() {
    // テスト成功
  , function(error) {
    // プラグインテスト失敗
  });
});

プラグインのテストに失敗した時にはアラートを出すのが良いでしょう。テストが成功したら、データベースを開きます。

2. データベースを開く

データベースへの接続を行います。接続情報は多くのメソッドで使われることになりますのでグローバル変数としておくのが良いでしょう。

var db = null;

// データベースを開く
db = sqlitePlugin.openDatabase({name: 'todo.db', location: 'default'});

3. テーブル作成(テーブルがなければ)

以下のような構造のTodoテーブルを作成します。

カラム名 データ型 キー
key integer 主キー
title text -
body text -

テーブルを作成する命令は、次のような形式になっています。

db.executeSql("SQL文", "引数", "SQL実行成功時のコールバック", "SQL失敗時のコールバック");

テーブルを作成するCREATE TABLE文を実行します。このときテーブルがなければ作成する IF NOT EXISTS を指定します。

// テーブル作成のSQL実行
db.executeSql("CREATE TABLE IF NOT EXISTS Todo (id integer primary key autoincrement, title text, body text)", [], function(res) {
     // テーブル作成成功
    }, function(error) {
      // テーブル作成失敗
      alert(error.message);
    });
  });
});

4. 既存データの取り出し

最後にTodoテーブルから既存データを取り出す処理を行います。

// データ取得のSQL実行
db.executeSql("SELECT * FROM Todo ORDER BY id desc", [], function(rs) {
  // 取得したデータを表示
  for (var i = 0; i < rs.rows.length; i++) {
    row = rs.rows.item(i);
    showTodo(row.title, row.body);
  }
}, function(error) {
  // データ取得失敗
  alert(error.message);
})

SELECT文の場合、 rs.rows.length で結果の件数が取得できます。そして、 rs.rows.item(i) (iは行数のインデックス)で行のデータが取得できます。カラムは row.title のように指定して取得できます。

アプリ起動時のコード全体は次のようになります。

var db = null;

document.addEventListener('deviceready', function() {
  // プラグインのテスト
  sqlitePlugin.selfTest(function() {
    // テスト成功
    // データベースを開く
    db = sqlitePlugin.openDatabase({name: 'todo.db', location: 'default'});
    // テーブル作成のSQL実行
    db.executeSql("CREATE TABLE IF NOT EXISTS Todo (id integer primary key autoincrement, title text, body text)", [], function(res) {
      // テーブル作成成功
      // データ取得のSQL実行
      db.executeSql("SELECT * FROM Todo ORDER BY id desc", [], function(rs) {
        // 取得したデータを表示
        for (var i = 0; i < rs.rows.length; i++) {
          row = rs.rows.item(i);
          showTodo(row.title, row.body);
        }
      }, function(error) {
        // データ取得失敗
        alert(error.message);
      })
    }, function(error) {
      // テーブル作成失敗
      alert(error.message);
    });
  }, function(error) {
    // プラグインテスト失敗
    alert(error.message);
  });

データの表示

データを表示する部分は元々のTodoアプリから少し変更しています。具体的には次の通りです。

  • 画像表示の削除(バイナリデータの保存は少し複雑になるので、今回は対応していません)
  • データの表示処理を関数化(showTodo)

内容は次の通りです。タスクのタイトルと本文を表示しています。

function showTodo(title, body) {
  $("#todo-list").append("<li><h3>" + title + "</h3><p>" + body + "</p></li>")
  $("#todo-list").listview('refresh');
}

データの追加

Todoを追加する処理です。写真は上述の通り削除しています。

function addTodo(camera_url) {
    // 入力データを取得
    var title = $("#todo-title").val();
    var body = $("#todo-body").val();
    $.mobile.changePage($("#list-page"));

    // データ追加のSQL実行
    db.executeSql("INSERT INTO Todo (title, body) values (?, ?)", [title, body], function(res) {
      // SQL成功。表示処理に
      showTodo(title, body);
    }, function(error) {
      // SQL失敗
      alert(error.message);
    });
};

INSERT文を実行する時にはSQLインジェクションに注意する必要があります。そのため、自分でエスケープ処理を書くのではなく引数を使って渡すようにした方が安全です。SQLが成功したらそのままアプリ起動時と同じように表示処理に渡しています。

なお、cordova-sqlite-storageはコールバック方式になっているのでネストが深くなる傾向があります。Promiseを使った方が見通しの良いコードになりそうです。

ここまでできあがったら、アプリを実行します。サードパーティ製のプラグインを使っているので、アプリのビルドが必要です。ビルドができたらアプリを起動してTodoを追加してみましょう。再読み込みしてもデータが消えずに表示されれば完成です。


今回のコードはmoongift/MonacaSQLiteDemoにアップロードされていますので参考にしてください。

なお、参考までにcordova-sqlite-storageはトランザクションやSQLバッチもサポートしています。

// トランザクション例
db.transaction(function(tx) {
   tx.executeSql('CREATE TABLE IF NOT EXISTS DemoTable (name, score)');
   tx.executeSql('INSERT INTO DemoTable VALUES (?,?)', ['Alice', 101]);
   tx.executeSql('INSERT INTO DemoTable VALUES (?,?)', ['Betty', 202]);
}, function(error) {
   console.log('Transaction ERROR: ' + error.message);
}, function() {
   console.log('Populated database OK');
});

// バッチSQLの例
db.sqlBatch([
  'CREATE TABLE IF NOT EXISTS DemoTable (name, score)',
  [ 'INSERT INTO DemoTable VALUES (?,?)', ['Alice', 101] ],
  [ 'INSERT INTO DemoTable VALUES (?,?)', ['Betty', 202] ],
], function() {
  console.log('Populated database OK');
}, function(error) {
  console.log('SQL batch ERROR: ' + error.message);
});

cordova-sqlite-storageを使いこなして、より便利なスマートフォンアプリを開発してください。

litehelpers/Cordova-sqlite-storage: A Cordova/PhoneGap plugin to open and use sqlite databases on Android, iOS and Windows with HTML5/Web SQL API