主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

Windowsのデスクトップアプリに使うデータベースにドキュメント指向データベースを使う

                
tags: couchbase
 オーディオライブラリ再生のユニバーサルアプリを作ってみた。
http://elicon.blog57.fc2.com/blog-entry-463.html
 アルバム情報を格納するデータベースにSQLiteを使った。できれば柔軟なドキュメント指向のデータベースが使いたかったが、それがまだなかったのでSQLiteを選んだ。
 SQLiteではアルバム一件の情報を保存しようと考えると、アルバムタイトルやアーティスト名を入れたアルバム情報のレコードと、そのレコードと結びつけられる情報を持った曲名や曲番を入れた曲情報に分散して保存する必要があるだろう。↑のユニバーサルアプリでは単純にしたかったので、工夫をしてアルバムと曲情報の分裂を避けて一件のレコードにそれらをまとめたが。
 ドキュメント指向のデータベースでJSONがドキュメントとなっているものを選べば、情報の収納にはJSONが使えるので柔軟な構成が可能で、工夫がいらずにCDアルバムの情報を一件のレコード(正しくはドキュメントと呼ぶ)にまとめられる。
 一件のドキュメントに柔軟に情報をまとめられる一方で、無理をすると情報構造が複雑になってしまう。複雑になる場合はわかりやすくきれいに切り分けたほうがいいこともあるだろうから、そこらへんはSQLiteのようなリレーショナルデータベースを選ぶのも吉。ただデータベース選択の一種としてドキュメント指向データベースも持っておきたいので、CDアルバムという例をとおしてドキュメント指向データベースの使い方を確認しておく。

 SQLiteと同様にローカルで使うことを目的としたドキュメント指向データベースにはCouchbase Liteがある。
http://developer.couchbase.com/mobile/get-started/couchbase-lite-overview/index.html
 動作ターゲットはLinux、Win、MacはもちろんiOS、AndroidからUnityもターゲットになっているので、デスクトップだけでなくスマフォアプリのデータベースとしても使えるだろう。今回は.NET Frameworkのデスクトップアプリで使う。

 VisualStudioでCouchbase Liteを入れたいプロジェクトを開く。Package Manage Consoleを開いて"Install-Package Couchbase.Lite"を実行。依存ライブラリとともにインストールが始まる。

 使用準備ができたら始める。依存ライブラリに入っているNewtonsoftのJsonツールも入っているので使えるようにしておくとデータの取り回しが楽になる。
http://www.newtonsoft.com/json/help/html/SerializingJSON.htm
using Couchbase.Lite;
using Newtonsoft.Json.Linq;


 データベース接続。
var dirInfo = new System.IO.DirectoryInfo(System.IO.Directory.GetCurrentDirectory());
var manager = new Manager(dirInfo, ManagerOptions.Default);
var db = manager.GetDatabase("foo");
if (db == null)
{
throw new Exception("Cannot create database.");
}


 ここで保存するアルバム情報のデータを考える。とりあえずアルバムタイトル、アーティスト名、収録曲名、リリース年あたりで構成。収録曲名をListにしたい、Listにするとリレーショナルデータベースでそのまま保存できないので今回のようにドキュメント指向データベース使用を考えようかとなってくる。
class Album
{
public string AlbumTitle { get; set; }
public string Artist { get; set; }
public List<string> TrackTitles { get; set; }
public int? Year { get; set; }

public static Album FromJson(string jsonstr)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<Album>(jsonstr);
}

public Dictionary<string, Object> GetDict()
{
var dict = new Dictionary<string, dynamic>() {
{"AlbumTitle", AlbumTitle},
{"Artist", Artist},
{"TrackTitles", TrackTitles},
{"Year", Year},
};
return dict;
}
}

 オブジェクトをDictionary化するメソッドも加えておいた。あとJSONからこのオブジェクトを作るメソッドも。

 適当なアルバム名やアーティスト名を入れてAlbumのインスタンスを準備。
var album1 = new Album()
{
AlbumTitle = "album1",
Artist = "artist1",
TrackTitles = new List<string> {"t1", "t2", "t3"},
Year = 2010
};

var album2 = new Album()
{
AlbumTitle = "album2",
Artist = "artist2",
TrackTitles = new List<string> { "t1", "t2", "t3", "t4", "t5" },
Year = 2005
};

var album3 = new Album()
{
AlbumTitle = "album3",
Artist = "artist1",
TrackTitles = new List<string> { "r1" },
Year = null
};

var albums = new List<Album> { album1, album2, album3 };


 データベースへそれぞれのアルバムデータを保存。
foreach (var album in albums)
{
var document = db.CreateDocument();
document.Id = album.Artist + " " + album.AlbumTitle;
var albumDict = album.GetDict();
albumDict["updated_at"] = DateTime.Now;
var properties = albumDict;
var rev = document.PutProperties(properties);
Console.WriteLine(rev);
}


 保存データの全件読み出し。
var view = db.GetView("all");
if (view != null)
{
view.SetMap((doc, emit) =>
{
emit(doc["AlbumTitle"], doc);
}, "ver1");
}

var vQuery = db.GetView("all").CreateQuery();
docs = vQuery.Run();
Console.WriteLine("no filter: " + docs.Count);


 読みだしたドキュメントをAlbumオブジェクトへ。
foreach (var doc in docs)
{
var album = Album.FromJson(doc.Value.ToString());
Console.WriteLine(album.AlbumTitle);
}


 t1というタイトルの曲が入ったアルバムを探す。
var view3 = db.GetView("TrackTitleFilter");
if (view3 != null)
{
view3.SetMap((doc, emit) =>
{
var titles = ((JArray)doc["TrackTitles"]).ToArray();
if (titles.Contains("t1"))
{
emit(doc["AlbumTitle"], doc);
}
}, "ver1");
}

var vQuery = db.GetView("TrackTitleFilter").CreateQuery();
docs = vQuery.Run();
Console.WriteLine("TrackTitle filter: " + docs.Count);


 データソートはemitというデリゲートに渡す第一引数で行われる。データのオーダーを気にする場合はその辺も気にかけて。
 CRUDで考えればドキュメント作成はした。ドキュメントの引き出しからオブジェクトへの変換も行ったのでデータも読める。更新や削除は引き出したドキュメントからメソッドを実行するだけである。
http://developer.couchbase.com/mobile/develop/guides/couchbase-lite/native-api/document/index.html

 デスクトップアプリにドキュメント指向データベースを使いたくなったのでCouchbase Liteの使い方を学んだ。サービスとしてAzureでもドキュメント指向データベースの提供は始まっており、それをローカルでも使えるようにしてくれという投票も行われている。ドキュメント指向データベースも場合によってはかなり使い物になるということだろうから使える箇所を考えていきたい。
スポンサーサイト



C#: Couchbase Liteを使ってみる

                
 .NETのプロジェクト一覧を見ていたらCouchbase Liteというドキュメント指向のデータベースが目についた。ドキュメント指向でいくらか有名なcouchbase serverのローカル版、RDBでいうところのSQLiteの立ち位置だろう。ユーザーがどれほどかはわからないが、WindowsデスクトップはもちろんiOSやAndroidも含めてかなり広い環境で使えるようになっているようだ。もちろんC#、Objectice-C、Javaなど様々な言語から使える。

 オプソになっているのでコードを見たければGithubへ。
https://github.com/couchbase/couchbase-lite-net

 VisualStudio2013環境で使ってみる。データベースを使うアプリケーションはデスクトップのWPFでやる。ターゲットCPUをAny CPUにしておくとビルド時にエラーが出るので64なり86なり考えて設定しておく。
https://github.com/couchbase/couchbase-lite-net/issues/355

 公式ドキュメントのGettingStartedを参考に準備をする。Couchbase LiteはNuGetを使えば依存関係も含めてプロジェクトへインストールされる。
http://developer.couchbase.com/mobile/get-started/get-started-mobile/net-mobile/create-new-project/index.html

 公式ドキュメントでデータベースの作成からクエリなどがある。データベースの初期化はManagerクラスにDirectoryInfoでデータ保存に使うディレクトリを与える。GettingStartedではDirectoryInfoを与えずにManagerを呼んでいるが、WindowsでそれをやるとマイドキュメントのAppDataというデフォルトで不可視のディレクトリにデータが保存されるので個人的に好みでない。
var dirInfo = new System.IO.DirectoryInfo(System.IO.Directory.GetCurrentDirectory());
var manager = new Manager(dirInfo, ManagerOptions.Default);


 CRUD操作はドキュメントそのままにやるだけ。とりあえず適当にドキュメント(RDBでいうところの行)を保存してみる。CDアルバムを一件のデータとして想定した。
var document = db.CreateDocument();
document.Id = "id_x" + i.ToString();
var properties = new Dictionary<string, object>()
{
{"albumTitle", "title" + i.ToString()},
{"artist", "artist" + i.ToString()},
{"titles", new List<string>{i.ToString()}},
{"files", new List<string>{i.ToString()}},
{"updated_at", DateTime.Now},
};
var rev = document.PutProperties(properties);
Console.WriteLine(rev);

DateTimeオブジェクトはToStringメソッドで文字列にして渡してもあとで使うときにDateTimeオブジェクトとしてもどってきていたのでToStringメソッドを抜いている。
 IDによるドキュメントの取得は下記のように。
var docById = db.GetDocument("id_x1");
Console.WriteLine(docById.GetProperty("albumTitle"));

 クエリはぼくが今まで使った他のデータベースと違って特徴があった。RDBならSQLを書けばよかったしMongoDBならdb.cd_album.find({artist:"Taylor Swift"})というふうにメソッドにJSON(あるいはそれを模擬する辞書型データ)を渡せば、条件にそったフィルタリングなどをして必要なデータを返すものが用意されていた。
 couchbase lite(おそらくcouchbaseも)ではViewというものを使う。Viewにストアされたドキュメントを必要な形にマッピングする関数をセットする。ストアされたデータをそのままひっぱってくることもできるが、必要なデータだけをひっぱってきて使いやすい形に整形する。ラムダ式を使って書けるようになっている。
var view = db.GetView("all");
view.SetMap((doc, emit) =>
{
emit(doc["albumTitle"], doc["artist"]);
}, "ver1");


var vQuery = db.GetView("all").CreateQuery();
docs = vQuery.Run();
foreach (var doc in docs)
{
Console.WriteLine("key: " + doc.Key);
Console.WriteLine("value: " + doc.Value);
}

関数emitに渡す第一引数がKey、第二引数がValueとして結果がマッピングされるようになっている。ちなみに同様のことはMongoDBでもできる。

 DateTime型を渡したupdated_atの値でフィルタをかけたければ以下のように書ける。
var view2 = db.GetView("datetimeFilter");
view2.SetMap((doc, emit) =>
{
if ((divTime.CompareTo((DateTime)doc["updated_at"])) > 0)
{
emit(doc["albumTitle"], doc);
}
}, "ver1");

マッピングの概念などは幸いに過去の公式ドキュメントが日本語化されたものが読める。
http://docs.couchbase.com/prebuilt/translations/jp/couchbase-manual-2.0-ja/couchbase-views-writing-map.html

 Couchbase Liteを使う利点はJSON形式でデータが保存できて、クロスプラットフォームなところだろう。でもこれってJSONじゃないけどSQLiteで……ユーザの数からしても困った時に解決法を探しやすいのはSQLiteのほうではないだろうかとは思う。
 クエリをRDBのようにSQLで行うわけでなく、同じドキュメント指向であるMongoDBのように指定されたメソッドに条件を与えて行うわけでもない。自分で処理する関数を書いて使える形にマッピングする。けっこう特徴的で面白いデータベースだと思う。
プロフィール

h

Author:h

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon