開発者が知っておくべき、ドキュメント・データベースの基礎特集:MongoDBで理解する「ドキュメント・データベース」の世界(前編)(1/3 ページ)

これまでドキュメント・データベースを触ったことがない開発者に向け、最もポピュラーな「MongoDB」を例にその本質を解説。

» 2012年11月09日 14時20分 公開
[国分 すばる,]
特集:MongoDBで理解する「ドキュメント・データベース」の世界(前編)
Insider.NET

 ドキュメント・データベースの最大の特長は、「パフォーマンス、大量データ、スケーラブルといった課題を克服するためのシンプルなセットを提供している」という点だ。

 もちろん既存の多くのリレーショナル・データベース(以下、RDB)でも、ドキュメント・データベースが備えている特徴的な各機能に類似することが実現可能だし、さらに広範な概念や機能性を提供している。例えばシャーディング(Sharding。詳細後述)についても、既存の多くのRDBでデータの分散化が可能だ。しかしドキュメント・データベースでは、「そもそもデータ構造がこうした構成に適している」という点と、「それに付随して、考え方もシンプルである」という点が優位な特徴である。

 万人が、データベースが持つ多数の機能や動きをすみずみまで理解し、最適な組み合わせとチューニングを行えるならよいが、現実にはそう容易ではない。問題は、「できるか、できないか」ではなく、「その目的を達成するために、いかに最適化されているか」という点だ。つまり、ドキュメント・データベースが特定の指向や用途にとって「シンプルな機能のセット」を提供しているという点が重要なのだ。

  そこでこの記事では、ドキュメント・データベース(=ドキュメント指向データベース)として最もポピュラーな「MongoDB」を例に、これまでドキュメント・データベースに触ったことがない技術者(特にプログラマー)の方を対象に、その本質を解説しようと思う。

ドキュメント・データベースの基礎

 後述するが、MongoDB自身は「固有の特徴」を持ったドキュメント・データベースだ。このため、本稿の前半はMongoDBを使って解説するが、後半でほかのドキュメント・データベースについても触れることで、MongoDBそのものが持つ固有の特徴にも気付いてもらえるよう書こうと思う。また、MongoDBの利用方法を解説するのが目的ではないので、インストール方法などの基本的なセットアップ方法に関する解説は省略する。

 まず、この後の解説に備え、ドキュメント・データベースの基本的な概念から解説したい。

「DB」「コレクション」「オブジェクト(=ドキュメント)」の概念

 MongoDBでは、「DB(=データベース)(dbs)」「コレクション(Collection)」「オブジェクト(Object。=ドキュメント:Document。以降、単に「オブジェクト」と表記)」の概念を操作する。

 例えば、MongoDBのコマンドライン・ユーティリティ「mongo」(=mongo.exeファイル)により「testdb」というDBを使用する場合は、以下のコマンドを実行する(なお、下記のコマンドを実行した段階では、まだDBは作成されず、オブジェクトを格納して初めてDBやコレクションの実体が作成される)。

mongo localhost:27017
> use testdb;


「mongo」コマンドにより、ポート「27017」のサーバ上の「testdb」というDBを使用する場合のコマンドライン入力例


 ドキュメント・データベースの最も特徴的な点は、RDBと異なり、スキーマを持っていないという点だ。そのため、さまざまな型のオブジェクトをそのまま登録できる。

 例えば、「testdb」の「Orders」コレクションにオブジェクトを挿入する場合は、以下のようなコマンドを実行する(この段階で初めて「testdb」というDBと「Orders」というコレクションの実体が作成され、そこに「obj1」として作成したオブジェクトが保存される)。あらかじめ定義された型にオブジェクトを登録するのではなく、匿名型のオブジェクトをそのまま登録できる(しかも、単一のコレクションに対して、異なる型のオブジェクトも登録できる)。

> obj1 = { Name : "test1", Price : 100, Category : "material" };
> db.Orders.save(obj1);


testdbのOrdersコレクションのsaveメソッドを呼び出すことで、オブジェクトを挿入
「obj1」の部分を見ると分かるように、MongoDBのオブジェクトは、JSON(JavaScript Object Notation)をベースとしたオブジェクト・フォーマット(=Notation)を使用している。


Key-Valueストア

 下記のコマンド例(クエリ)では、登録された全てのオブジェクトを取得している。その取得結果を見ると分かるが、必ず、「_id」(=識別子)が登録されている。このように、Key-Valueストア(KVS)を使用した“NoSQL”データベースであるドキュメント・データベースでは、必ずKey(MongoDBの場合、既定で「_id」)が付与される。

> db.Orders.find()

{ "_id" : ObjectId("5080df68758966a4fcc6d235"), "Name" : "test1", "Price" : 100, "Category" : "material" }


Ordersコレクションのfindメソッドを呼び出すことで、全オブジェクトを取得


 このKey-Valueの構造により、オブジェクトの特定が高速化され、(後述するように)スケーラビリティが実現される。これらの特徴を実現するうえで、こうしたKeyの存在は必要不可欠となる。

 また、ドキュメント・データベースでは、(この後で述べるように)インデックスによって、こうしたオブジェクト特定のためのKeyを追加することも可能だ。すなわち、ここで使用される「_id」は、「最初に割り当てられるKeyの1つ」と考えてよい(もちろん、MongoDB内部では随所でこの「_id」を使用しており、ほかのKeyとは明確に異なる性質を持ったKeyだ)。

検索機能

 MongoDBでは、簡単な検索も可能だ。例えば、上記のOrdersコレクションで、Nameフィールドが「test1」の値を検索する場合は下記のとおりだ(後述するが、MongoDBでは、明示的にインデックスを作成していない場合、こうした検索は遅くなる場合があるので注意してほしい)。

> db.Orders.find({Name:"test1"});


パラメータに検索値を指定してOrdersコレクションのfindメソッドを呼び出すことで特定のオブジェクトを検索


 また例えば、Priceフィールドの値が「50」を超えるオブジェクトを検索する場合は、下記のとおりだ。「$gt」は、“greater than”(すなわち、「……より大きい」)を意味している。ほかにも「$and」「$or」はもちろん、「$all」「$exsists」などの条件演算子を指定して、さまざまな検索が可能だ。

db.Orders.find({Price: {$gt: 50}});


条件を指定して検索


MongoDBアクセス用の各言語のドライバ

 MongoDBは、(ここまで見てきたように)JSONをベースとしたオブジェクト・フォーマット(=Notation)を使用するなど、各種開発言語との親和性に配慮したデータベースとなっている。実際、数多くの開発言語からMongoDBにアクセスできる(例えば「C」「C++」「Erlang」「Haskell」「Java」「Javascript」「.NET(C#/F#/PowerShellなど)」「Node.js」「Perl」「PHP」「Python」「Ruby」「Scala」など)。

 外部のプログラムなどからMongoDBへのアクセスする際には独自のプロトコルが使用されるので、各開発言語向けに専用のドライバ(driver)が提供されている。.NET開発者にとっては、MongoDB開発元の10gen社による公式のC#言語用ドライバ「Official MongoDB C# driver」(以降、C# driver)が提供されている(C# driverは、NuGetから取得できる)。

NuGet経由でC# driverをインストールしているところ

 試しにC#を使って、上記のコマンド・ラインで実行した処理(つまり、オブジェクトの作成と検索)と同じことを書くと、下記のコードのようになる。

using System;
using MongoDB.Driver;
using MongoDB.Bson;

class Program
{
  static void Main(string[] args)
  {
    MongoServer server = MongoServer.Create(@"mongodb://localhost");
    MongoDatabase db = server["testdb"];

    MongoCollection<Order> col = db.GetCollection<Order>("Orders");

    // saveメソッド
    Order obj1 = new Order()
    {
      Name = "test1",
      Price = 100,
      Category = "material"
    };
    col.Insert(obj1);

    // findメソッド
    MongoCursor<Order> sel1 = col.FindAll();
    foreach (var item in sel1)
    {
      Console.WriteLine("_id : {0}, Name : {1}", item._id, item.Name);
    }

    Console.ReadLine();
  }
}

public class Order
{
  public ObjectId _id { get; set; }
  public string Name { get; set; }
  public int Price { get; set; }
  public string Category { get; set; }
}


C# driverを使ってオブジェクトの作成と検索を行うC#のコード例(コンソール・アプリケーション)


 このプログラミング・スタイルを見て分かると思うが、オブジェクト・データベース(=オブジェクト指向データベース)などと同様、プログラムで扱うオブジェクトをそのままの形で扱うことができる(データベース専用の様式に変換せず、オブジェクトをそのままシリアライズ、逆シリアライズする概念だ)。スキーマを持っていないため、RDBを扱う際のような、データベースへのマッピング定義や、データベース・スクリプトの生成処理などは一切不要だ。

「MongoDB」+「C#」+『LINQ』が便利

 また、せっかくC#を使うなら、言語の利点を十分に生かしたい。そう、C#開発者にはおなじみのLINQを使うことで、より直感的に“アドホック・クエリ(Ad-hoc query)”を実行できる。MongoDBの以前のバージョン(バージョン1.4以前)は、LINQを使うには「FluentMongo」という追加のライブラリを使うしかなかったが、現在のC# driverではLINQ用の拡張メソッドが標準で含まれている(ただし、これらは同一ではないので注意してほしい。例えばクエリからMapReduce関数(後述)を自動生成できるなど、現在でもFluentMongoを使う意義は十分ある)。

 実際にMongoDB+LINQのプログラムを書いてみよう。例えば上記のFindAllメソッドの部分のコードをC# driverのLINQを使って記述すると、下記のようになる。

using System.Linq;
using MongoDB.Driver.Linq;

// find (Linq)
var sel1 = from c in col.AsQueryable<Order>()
           select c;
foreach (var item in sel1)
{
  Console.WriteLine("_id : {0}, Name : {1}", item._id, item.Name);
}


MongoDB+LINQのコード例(一部抜粋)


 名前で検索する場合には、下記のとおりになる。上記のMongoDB固有なQueryシンタックスと比較すると、一目瞭然なように、SQLとほぼ同じシンタックスでMongoDBを扱うことが可能だ。

// find (Linq)
var sel1 = from c in col.AsQueryable<Order>()
  where c.Name == "test1"
  select c;


where条件を指定するなど、SQLとほぼ同じシンタックスでMongoDBを扱えることを示すコード例


 なお、ここでは詳細を省略するが、C# driverで使用可能なLINQ構文については、mongoDB.orgの「CSharp Driver LINQ Tutorial」(英語)を参照してほしい。

MongoDB独自のプロトコルではなく、汎用的なREST形式でアクセスする方法

 「RavenDB」など、ほかのドキュメント・データベースの多くはRESTによるアクセスをベースとしているが、上記のとおり、MongoDBでは、各言語用のドライバを使用している(例えば、次回で説明するRavenDBでは、RESTの上に言語用のAPIが実装されている)。しかし、MongoDBでも、下記のとおりオプションを指定して起動(もしくは、サービスやデーモンとして登録)することでRESTによるアクセスが可能だ。

mongod --rest


REST形式によるアクセスを可能にするオプションを指定してMongoDB(=mongod.exeファイル)を起動するコマンド


 RESTを使うと、言語用のドライバが提供されていない環境でも、HTTPを扱うことができれば、MongoDBの操作を呼び出して使用することができる。

 次のページでは、ドキュメント・データベースらしい利点に着目してMongoDBの特徴をさらに掘り下げていく。

       1|2|3 次のページへ

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。