Spring Roo 入門: 第 7 回 Spring Roo を使って Spring MongoDB アプリケーションを開発する

エンタープライズ Spring MongoDB アプリケーションを迅速に構築する

MongoDB は、非常によく使われている、水平スケーリング可能なドキュメント指向の NoSQL データストアです。Spring Roo バージョン 1.2 では、MongoDB をデータ・ストレージ・ソリューションとして使用した Spring アプリケーションを構築することができます。この記事では MongoDB について紹介した後、Spring Roo を使ってエンタープライズ Spring MongoDB アプリケーションを構築します。

Shekhar Gulati, Senior Java Consultant, Xebia

Photo of Shekar GulatiShekhar Gulati は、Xebia India の Java コンサルタントです。これまで 6 年以上、Enterprise Java の経験があり、Spring、Spring-WS、Spring Roo など、一連の Spring プロジェクトに関する幅広い経験を持っています。彼が関心を持っている分野には、Spring、NoSQL データベース、Hadoop、Spring Roo のような RAD フレームワーク、クラウド・コンピューティング (主に Google App Engine、CloudFoundry、OpenShift などの PaaS サービス) などがあります。彼は執筆活動も活発に行っていて、JavaLobby、Developer.com、IBM developerWorks、そして彼自身のブログ (http://whyjava.wordpress.com) などに寄稿しています。Twitter で彼をフォローするには、http://twitter.com/#!/shekhargulati にアクセスしてください。



2012年 10月 04日

Spring Roo を話題にしたこの連載の第 6 回では、Spring Roo 1.2 で導入された数々の新機能を紹介しました。その記事で取り上げた新機能のうちの 1 つが、MongoDB アプリケーションを構築するためのサポートです。Spring Roo MongoDB は、生産性の強化、そして一貫したプログラミング・モデルという従来の Spring の提案を、MongoDB アプリケーションにも適用することを目的としています。Spring MongoDB は、Spring Data のサブプロジェクトです。Spring Data はオープンソースのアンブレラ・プロジェクトであり、それぞれに特定のデータストアを対象とした多数のサブプロジェクトからなります。今回の記事では、MongoDB について紹介した後、Spring Roo を使って Spring MongoDB アプリケーションを構築します。

MongoDB の紹介

MongoDB を一文で表現すると、MongoDB はオープンソース、ドキュメント指向、スキーマレス、高速処理、水平スケーリング対応という特徴を持つ NoSQL データストアです。この表現には、理解しておかなければならない非常に重要な 5 つのキーワードがあります。これらのキーワードについて順に説明します。

  1. ドキュメント指向: MongoDB には、リレーショナル・データベースのような行の概念はなく、代わりにドキュメントという概念があります。MongoDB は、ドメイン・オブジェクトと密接に対応するバイナリー JSON (BSON) ドキュメントという形でデータを保管します。MongoDB には、結合の概念がありませんが、ネストされたオブジェクトを使用することができます。例として、ブログとコメントという 2 つのドメイン・オブジェクトがあるブログ・アプリケーションを考えてみてください。リレーショナル・データベースでは、ブログはコメント・テーブルと 1 対多の関係を持つため、1 つのブログに対する複数のコメントをフェッチするには、結合が必要です。MongoDB では、結合を使用する代わりに、ネストされたドキュメントを使用します。リスト 1 に、コメントの配列を持つブログ・ドキュメントの例を記載します。この場合、結合を使用しなくても、ブログに対するすべてのコメントをフェッチすることができます。MongoDB には充実したクエリー機能が揃っているため、必要なフィールドと要素を簡単に抽出することができます。

    リスト 1. ネストされた配列の例
    { 
        "author" : "shekhar", 
        "text" : "Hello MongoDB", 
        "title" : "Hello MongoDB" 
        "comments" : [ 
            { 
                "name" : "anonymous", 
                "comment" : "good blog" 
            }, 
            { 
                "name" : "guest", 
                "comment" : "awesome blog" 
            } 
        ], 
    }
  2. スキーマレス: RDBMS では行がテーブルに保管されるように、MongoDB のドキュメントはコレクションに保管されます。ただし、MongoDB は、コレクションに厳密なスキーマを定義するように強要しません。MongoDB に保管するドキュメントは、コレクション内にすでに保管されているドキュメントとまったく違っていても構いません。MongoDB コレクションに保管されるドキュメントは、それぞれに種類が異なり、他のドキュメントと完全に異なる構造を持つことができます。つまり、ブログ・ドキュメントと作成者ドキュメントの両方を同じ 1 つのコレクションに保管することができます (リスト 2 を参照)。

    リスト 2. MongoDB コレクションの例
    {"author" : "shekhar", "text" : "Hello MongoDB","title" : "Hello MongoDB"}
    {"fullname":"Shekhar Gulati","email":"shekhargulati84@gmail.com","password":"xxxxxx"}
  3. 高速処理: MongoDB は、書き込みと読み取りの両方に関してハイパフォーマンスのデータストアです。デフォルトの構成では、MongoDB の書き込みパフォーマンスは、RDBMS よりも高くなっています。それは、書き込みは「ファイア・アンド・フォーゲット」の方式で行われるため、データを RAM に書き込んでおけば、後は適当なタイミングで自動的にディスクに書き込まれるからです。MongoDB の書き込み動作を制御するには、書き込み操作と併せて WriteConcern の値を指定します。WriteConcern には、以下の値があります。

    1. Normal: これがデフォルトの値です。この値を指定すると、すべての書き込み操作がファイア・アンド・フォーゲットで行われるため、ドライバーにデータを書き込むだけで制御が返されます。サーバー上で書き込みが可能になるまで待機することはありません。したがって、ドキュメントが書き込まれた直後に、別のスレッドがそのドキュメントを読み取ろうとすると、該当するドキュメントを見つけられない場合があります。この値を指定した場合、極めて高いデータ損失の可能性があります。データの耐久性が重要であり、MongoDB サーバーのインスタンスを 1 つしか使用しない場合には、この値を使用することを検討しないでください。

    2. None: これは、Normal とほとんど同じで、1 つの点が異なるだけです。Normal では、ネットワークがダウンした場合や、ネットワークに関する別の問題が発生すると、例外を受け取ります。None では、ネットワークの問題が発生しても例外を受け取りません。したがって、かなり信頼性に欠けるオプションです。

    3. Safe: 名前からわかるように、この値を指定した場合、Normal や None を指定するよりも安全です。書き込み操作は MongoDB サーバーが書き込みを確認応答するまで待機します。ただし、この時点では、データはまだディスクに書き込まれていません。そして、別のスレッドが書き込み直後のオブジェクトを読み取ろうとして、オブジェクトを見つけられないといった問題は発生しません。いったん書き込まれたオブジェクトは必ず見つかります。その点は優れていますが、それでもまだ、データが失われる可能性はあります。データがディスクに書き込まれる前に何らかの理由でサーバーが停止すると、データは失われるからです。

    4. Journal Safe: この値について説明する前に、MongoDB でのジャーナリングについて説明しておきます。MongoDB でのジャーナリングとは、すべての操作について、書き込み前のログ・ファイルを維持する機能です。例えば、kill -9 コマンドを使用するなどして MongoDB が正常にシャットダウンされなかった場合には、ジャーナル・ファイルからデータを復旧することができます。デフォルトでは、100 ミリ秒 (ms) 間隔でデータがジャーナル・ファイルに書き込まれます。この間隔は、2 ms から 300 ms までの範囲で変更することができます。バージョン 2.0 ではデフォルトで、64 ビット MongoDB サーバー上でジャーナリングが有効に設定されます。WriteConcern に Journal Safe を指定すると、書き込みは、ジャーナル・ファイルが更新されてから行われます。

    5. Fysnc: WriteConcern に Fsync を指定すると、サーバーがデータをディスクにフラッシュするまで、書き込み操作が待機します。この場合、ハード・ディスクがクラッシュしない限り、データが失われることはありません。したがって、単一ノードでは、この値を指定しておくのが最も安全です。

    「How MongoDB Different Write Concern Values Affect Performance On A Single Node?」というタイトルの私のブログ投稿 (「参考文献」を参照) に詳細を説明しているので、詳しいことに関してはこのブログ投稿を読んでください。

  4. 水平スケーリング対応: MongoDB は、水平スケーリング可能なデータストアです。これは、MongoDB がより多くの読み取り/書き込みを処理し、さらに多くのMongoDB サーバーをクラスターに追加できることを意味します。水平スケーリングを可能にするために、MongoDB ではシャーディングを使用しています。シャーディングでは、アプリケーションのパフォーマンスに影響を与えることなく負荷とデータの増加に対処するために、MongoDB インスタンスが追加されます。最大の利点は、アプリケーションがシャーディングを行わなくてよいことです。シャーディングは、MongoDB によって自動的に行われます。自動シャーディングについてはこの記事では説明しません。シャーディングに関しては、「参考文献」に記載されている MongoDB マニュアルへのリンクを参照してください。

  5. NoSQL: おそらく皆さんはこの数年の間に、NoSQL という言葉を耳にしたことがあるはずです。NoSQL とは、Not Only SQL の頭辞語です。NoSQL は、RDBMS モデルに従わず、SQL を主要な問い合わせ言語として使用しないデータストア全般を指します。MongoDB は問い合わせ言語をサポートしていますが、それは、SQL のようなものではなく、JSON ドキュメントをベースとした問い合わせ言語です。

MongoDB は、RDBMS と同様の操作 (索引、クエリー、explain plan、および group などの集約関数) をサポートしています。それは、RDBMS に近いものにすることで、すぐに MongoDB を習得できるようにするためです。MongoDB でサポートされている優れた機能には、Map Reduce ジョブおよび地理空間の索引付けとクエリーを実行できることも挙げられます (「参考文献」に記載のドキュメントを参照)。

MongoDB の用語

MongoDB の用語は非常に単純なので、すぐに理解して覚えることができます。表 1 に、リレーショナル・データベースの用語との比較を記載します。

表 1. MongoDB とリレーショナル・データベースの用語の比較
RDBMSMongoDB

データベース

データベース

テーブル

コレクション

ドキュメント

MongoDB では、あらゆるものがデータベース内に保管されます。データベースは、コマンドを使用して作成することができます。RDBMS では、データベースを複数のテーブルで構成できるのと同じく、MongoDB のデータベースも、複数のコレクションで構成することができます。また、RDBMS では、テーブルを複数の行で構成できるのと同じく、MongoDB のコレクションも、複数のドキュメントで構成することができます。異なる点は、RDBMS では、行の構造が固定され、その構造がすべてのメンバーに適用されることです。その一方、MongoDB では、ドキュメントの構造には柔軟性があり、同じコレクション内の 2 つのドキュメントがまったく異なる構造を持つこともできます。


MongoDB の基本操作

MongoDB を操作する前に、次の 4 つのプロセスに従って MongoDB をダウンロードし、MongoDB サーバーを実行してください。

  1. MongoDB をダウンロードします。MongoDB Web サイト (「参考文献」を参照) から、お使いのオペレーティング・システムに対応する MongoDB の最新バージョン (現在、2.0.4) の tarball または zip ファイルをダウンロードすることができます。

  2. MongoDB をダウンロードしたら、zip ファイルを任意の場所に解凍して、zip に含まれるシェル・ファイルを実行可能にします。

  3. コマンドラインから、解凍された MongoDB インストール・ディレクトリーの bin フォルダーに移動して、mongod を実行します。デフォルトでは、MongoDB はすべてのデータを /data/db に保管するので、このディレクトリーを作成して、該当するユーザーを所有者にする必要があるかもしれません。あるいは、デフォルトの /data/db ディレクトリーを使用する代わりに、dbpath 属性で任意の保管先を指定することもできます (リスト 3 を参照)。

リスト 3. MongoDB を起動する
shekhar@shekhar:~/tools/mongodb/mongodb2/bin$ ./mongod 
--dbpath=/home/shekhar/data/db 
Sat Mar 31 19:16:48 
Sat Mar 31 19:16:48 warning: 32-bit servers don't have journalling enabled by 
default. Please use --journal if you want durability. 
Sat Mar 31 19:16:48 
Sat Mar 31 19:16:48 [initandlisten] MongoDB starting : pid=6033 port=27017 
dbpath=/home/shekhar/data/db 32-bit host=shekhar 
Sat Mar 31 19:16:48 [initandlisten] 
Sat Mar 31 19:16:48 [initandlisten] ** NOTE: when using MongoDB 32 bit, you 
are limited to about 2 gigabytes of data 
Sat Mar 31 19:16:48 [initandlisten] ** see 
http://blog.mongodb.org/post/137788967/32-bit-limitations 
Sat Mar 31 19:16:48 [initandlisten] ** with --journal, the limit is lower 
Sat Mar 31 19:16:48 [initandlisten] 
Sat Mar 31 19:16:48 [initandlisten] db version v2.0.1, pdfile version 4.5 
Sat Mar 31 19:16:48 [initandlisten] git version: 
3a5cf0e2134a830d38d2d1aae7e88cac31bdd684 
Sat Mar 31 19:16:48 [initandlisten] build info: Linux domU-12-31-39-01-70-B4 
2.6.21.7-2.fc8xen #1 SMP Fri Feb 15 12:39:36 EST 2008 i686 BOOST_LIB_VERSION=1_41 
Sat Mar 31 19:16:48 [initandlisten] options: { dbpath: "/home/shekhar/data/db" } 
Sat Mar 31 19:16:48 [websvr] admin web console waiting for connections on port 28017 
Sat Mar 31 19:16:48 [initandlisten] waiting for connections on port 27017

MongoDB サーバーを起動した後、http://localhost:28017/ にアクセスすると、サーバーの Web コンソールに基本情報が表示されます。有用な操作を行うには、クライアントが必要です。MongoDB では、bin フォルダーに mongo という名前のコマンドライン・クライアントを用意しています。

クライアントを起動するには、./mongo を実行します。すると、リスト 4 に記載する出力が表示されます。

リスト 4. MongoDB クライアントを起動する
shekhar@shekhar:~/tools/mongodb/mongodb2/bin$ ./mongo 
MongoDB shell version: 2.0.1 
connecting to: test

リスト 4 の出力には、mongo クライントが test データベースに接続したことが示されています。サーバーとの接続が確立すれば、後はコレクションにドキュメントを挿入したり、ドキュメントを検索したりするなど、さまざまな操作を実行することができます。

データベースを作成する

まずは、データベースを作成しましょう。MongoDB には、データベースを作成するためのコマンドはありません。use コマンドでデータベースを選択するだけで、そのデータベースが自動的に作成されます (リスト 5 を参照)。

リスト 5. データベースを選択する
> use springroopart7
switched to db springroopart7

リスト 5 のコマンドは、springroopart7 という名前のデータベースを作成した後、新しく作成されたデータベースにコンテキストを切り替えます。このコマンドがデータベースを作成するのは、そのデータベースが存在しない場合のみです。既存のデータベースがある場合には、クライアントをそのデータベースに切り替えます。

コレクションを作成する

データベースを作成した後のステップは、当然、データベース内にコレクションを作成することです。コレクションを作成するには、db.createCollection() 操作を使用します (リスト 6 を参照)。

リスト 6. コレクションを作成する
> db.createCollection("blogs") 
{ "ok" : 1 }

リスト 6 では、「blogs」という名前のコレクションを作成するための操作を実行した後、MongoDB から、正常にコレクションが作成されたという応答が返されています。

コレクションを作成するもう 1 つの方法は、ドキュメントをコレクションに保存する方法です。指定されたコレクションが存在しなければ、MongoDB によってそのコレクションが作成されます。コレクションが存在する場合、MongoDB は既存のコレクションにドキュメントを追加します。次は、この操作について説明します。

ドキュメントを挿入する

blogs コレクションが用意できたので、次は、このコレクションにブログを挿入します。それには、JSON ドキュメントを作成する必要があります。そして、そのドキュメントをコレクションに挿入します (リスト 7 を参照)。

リスト 7. JSON を挿入する例
> db.blogs.insert({"author":"shekhar","title" : "Getting started with MongoDB",
"text":"MongoDB is an open-source document oriented, schema-free, fast and horizontally 
        scalable NoSQL datastore", 
"tags":["mongodb","nosql"]})

リスト 7 のコマンドは、新しいブログ・ドキュメントを作成し、そのドキュメントを blogs コレクションに挿入します。ご覧のように、これは tags 配列フィールドを含む、かなりリッチなドキュメントなので、特定のタグに対応するすべてのブログに対するクエリーを簡単に実行することができます。使用できるフィールドには、テキスト型、数値型、日付型、配列型をはじめ、さまざまな型があります。

ドキュメントを検索する

今のところ、コレクション内に永続化されているドキュメントは 1 つしかないので、そのドキュメントを表示するには、findOne 操作を使用することができます。この操作は、該当するコレクション内にある任意の 1 つのドキュメントを返すか、指定されたクエリーと一致する最初のドキュメントを返します。blogs コレクション内の任意の 1 つのドキュメントを検索する場合は、リスト 8 のコマンドを実行します。

リスト 8. ドキュメントの検索による出力例
> db.blogs.findOne() 
{ 
    "_id" : ObjectId("4f784a1c61d2e3bcf01bcff6"), 
    "author" : "shekhar", 
    "title" : "Getting started with MongoDB", 
    "text" : "MongoDB is an open-source document oriented, schema-free, fast and 
horizontally scalable NoSQL datastore", 
    "tags" : [ 
        "mongodb", 
        "nosql" 
    ] 
}

作成者 (“author”) が “shekhar” のドキュメントを 1 つだけ検索する場合は、db.blogs.findOne({"author":"shekhar"}) を実行します。

タグ (“tags”) を検索基準にしてクエリーを実行する場合は、リスト 9 のコマンドを実行します。ご覧のとおり、このクエリーは前のクエリーと同じように見えます。

リスト 9. クエリーを指定した findOne の出力例
> db.blogs.findOne({"tags":"mongodb"}) 
{ 
    "_id" : ObjectId("4f784a1c61d2e3bcf01bcff6"), 
    "author" : "shekhar", 
    "title" : "Getting started with MongoDB", 
    "text" : "MongoDB is an open-source document oriented, schema-free, fast and 
horizontally scalable NoSQL datastore", 
    "tags" : [ 
        "mongodb", 
        "nosql" 
    ] 
}

これまでのクエリーは 1 つのドキュメントだけを返しますが、作成者 (“author”) が “shekhar” で、タグ (“tags”) が “mongodb” となっているすべてのドキュメントを検索する場合は、> db.blogs.find({"author":"shekhar","tags":"mongodb"}) という find メソッドを使用します。

知っておかなければならない 1 つの点は、find メソッドはドキュメントを返すのではなく、カーソルを返すことです。デフォルトでは、MongoDB クライアントに最初の 10 個のドキュメントが表示されます。すべてのドキュメントを表示するには、返されたカーソルで結果を繰り返し処理します (リスト 10 を参照)。

リスト 10. 複数の繰り返し処理でドキュメントを表示する例
> var cursor = db.blogs.find({"author":"shekhar","tags":"mongodb"}) 
> while(cursor.hasNext())printjson(cursor.next()) 
{ 
    "_id" : ObjectId("4f784a1c61d2e3bcf01bcff6"), 
    "author" : "shekhar", 
    "title" : "Getting started with MongoDB", 
    "text" : "MongoDB is an open-source document oriented, schema-free, fast and 
horizontally scalable NoSQL datastore", 
    "tags" : [ 
        "mongodb", 
        "nosql" 
    ] 
}

その他のコマンド

MongoDB では、他にもさまざまなコマンドを実行することができます。コレクションで使用できるすべての操作を表示するには、リスト 11 に記載する help コマンドを入力してください。ここではリストを簡潔にするために、すべてのコマンドを表示してはいません。このコマンドをお使いの mongo クライアントで実行すると、すべてのコマンドが表示されます。

リスト 11. help コマンドの出力例
> db.blogs.help() 
DBCollection help
db.blogs.find().help() - show DBCursor help 
db.blogs.count() 
db.blogs.dataSize() 
db.blogs.distinct( key ) - for example db.blogs.distinct( 'x' ) 
db.blogs.drop() drop the collection 
db.blogs.dropIndex(name) 
db.blogs.dropIndexes() 
db.blogs.ensureIndex(keypattern[,options]) - options is an object with these 
possible fields: name, unique, dropDups 
db.blogs.reIndex() 
db.blogs.find([query],[fields]) - query is an optional query filter. fields is 
optional set of fields to return.

これで MongoDB の基本知識は身に付いたので、次は、MongoDB をデータストアとして使用する Spring アプリケーションを作成する作業に進みます。ここからは、MongoDB マニュアルや、developerWorks に公開されている MongoDB に関する記事を参考にすることができます (「参考文献」を参照)。


スキーマの設計

これから、ShortNotes という名前のアプリケーションを作成します。このアプリケーションには、Notebook (メモ帳) と Note (メモ) という 2 つのドメイン・オブジェクトがあります。メモ帳は、多数のメモで構成することができます。このアプリケーションのスキーマを設計するには、いくつかの方法があるので、それぞれのスキーマ設計の選択肢を見ていきましょう。

Note が配列として組み込まれた Notebook

ドキュメント・データストアにとって至極当然と思えるスキーマ設計は、Notebook ドキュメントに Note ドキュメントの配列をネストして組み込むというものです。この設計では、結合を使うことなく、リッチなドメイン・モデルが実現されます。リスト 12 に、Note ドキュメントの配列が組み込まれた 2 つの Notebook ドキュメントを保管する Notebook コレクションを示します。

リスト 12. 配列を組み込むスキーマの例
{ 
    "_id" : ObjectId("4f7ff4c9c2fceff338eb9a82"), 
    "name" : "MongoDB Notebook", 
    "author" : "shekhar", 
    "created" : ISODate("2012-04-07T08:02:59.572Z"), 
    "notes" : [ 
        { 
             "_id" :"f7ff4c9c2fceff338eb9a443"
            "title" : "Getting Started with MongoDB", 
            "note" : "Getting Started with MongoDB", 
            "created" : ISODate("2012-04-07T08:02:59.572Z") 
        }, 
        { 
            "_id" :"efvvgf7ff4c9ceff338eb9a443"
            "title" : "Setting up Replication", 
            "note" : "Setting up Replica Set in MongoDB", 
            "created" : ISODate("2012-04-07T08:02:59.572Z") 
        }
    ] 
} 
{ 
    "_id" : ObjectId("4f7ff4dcc2fceff338eb9a83"), 
    "name" : "MongoDB Notebook", 
    "author" : "tom", 
    "created" : ISODate("2012-04-07T08:03:31.491Z"), 
    "notes" : [ 
        { 
            "_id" :"be7ff4c332fceff338eb9a443"
            "title" : "Getting Started with MongoDB", 
            "note" : "Getting Started with MongoDB", 
            "created" : ISODate("2012-04-07T08:03:31.491Z") 
        }, 
        { 
            "_id" :"aaff4c9c3fceff338eb9a443"
            "title" : "Setting up Sharding", 
            "note" : "Setting up Sharded Cluster in MongoDB", 
            "created" : ISODate("2012-04-07T08:03:31.491Z") 
        } 
    ] 
}

リスト 12 のスキーマはなかなか良さそうです。このスキーマでは、メモ帳とメモに対してクエリーを実行することができます。

名前 (“name”) が “MongoDB Notebook” で、作成者 (“author”) が “shekhar” のメモ帳をすべて検索するには、以下のクエリーを作成します。

 db.notebooks.find({"name":"MongoDB Notebook","author":"shekhar"})

また、以下のコマンドによって、メモに対するクエリーも極めて簡単に実行することができます。

db.notebooks.findOne({"notes._id":"be7ff4c332fceff338eb9a443"})

配列に含まれる特定の Note ドキュメントを更新する必要がある場合や、特定の要素を配列から削除しなければならない場合は、少し複雑になってきます。$set および $pull 修飾子を使用すれば、これらの操作を行うことができますが、それには、これらの修飾子に関する十分な知識が必要です。リスト 13 の例では、ID (“_id”) が “f7ff4c9c2fceff338eb9a443” のメモと、作成者 (“author”) が “shekhar” のメモ帳を削除します。

リスト 13. $set、$pull 修飾子を使用してメモを削除する例
> db.notebooks.update({"author":"shekhar"},{"$pull":{"notes":
{"_id":"f7ff4c9c2fceff338eb9a443"}}}) 
> 
> 
> db.notebooks.findOne({"author":"shekhar"}) 
{ 
    "_id" : ObjectId("4f80137fc2fceff338eb9a8a"), 
    "author" : "shekhar", 
    "created" : ISODate("2012-04-07T10:14:01.827Z"), 
    "name" : "MongoDB Notebook", 
    "notes" : [ 
        { 
            "_id" : "efvvgf7ff4c9ceff338eb9a443", 
            "title" : "Setting up Replication", 
            "note" : "Setting up Replica Set in MongoDB", 
            "created" : ISODate("2012-04-07T10:14:01.827Z") 
        } 
    ] 
}

このスキーマには、いくつかの問題があります。

  1. このスキーマに伴う 1 つ目の問題は、特定のメモを検索できないことです。”_id” が "f7ff4c9c2fceff338eb9a443" に設定されたメモを検索する場合、リスト 14 のようにすれば、該当するメモに対するクエリーを簡単に実行できると思うかもしれません。

    リスト 14. ID を基準にメモを削除しようとする例
    > db.notebooks.find({"notes._id":"f7ff4c9c2fceff338eb9a443"})
    >{ 
        "_id" : ObjectId("4f7ff9edc2fceff338eb9a84"), 
        "name" : "MongoDB Notebook", 
        "author" : "shekhar",
        "created" : ISODate("2012-04-07T08:24:41.782Z"),
        "notes" : [ 
            { 
                "_id" : "f7ff4c9c2fceff338eb9a443",
                "title" : "Getting Started with MongoDB", 
                "note" : "Getting Started with MongoDB",
                "created" : ISODate("2012-04-07T08:24:41.782Z")
            },
            {
                "_id" : "efvvgf7ff4c9ceff338eb9a443",
                "title" : "Setting up Replication",
                "note" : "Setting up Replica Set in MongoDB",
                "created" : ISODate("2012-04-07T08:24:41.782Z")
            }
        ]
    }

    上記によって返されるのは、すべてのメモが含まれるメモ帳オブジェクトです。必要なメモ・オブジェクトを取得するには、フィルタリング処理のすべてをクライアント側で行わなければなりません。この機能に対するリクエストは MongoDB jira (「参考文献」を参照) に記録されているので、将来的にはこの機能が登場することになるでしょう。

  2. 直面する可能性がある 2 つ目の問題は、1 つの Notebook ドキュメントに数千もの Note ドキュメントが保管されている場合に生じる問題です。この場合、単一の MongoDB ドキュメントのサイズは 16MB に制限されているため、MongoDB に対する書き込みが失敗する可能性があります。単一のドキュメントのサイズが 16MB を超える場合、スキーマを正規化して複数のコレクションに分けることを検討してください。

  3. 3 つ目の問題は、サイズが大きいメモが数千ある場合に生じる問題です。この場合、クライアント側でメモリーの問題が発生する可能性があります。このようなシナリオの場合は、MongoDB の $slice 演算子を使ってページ分けすることを検討してください。

リレーション手法: Notebook と Note を別々のコレクションとして分離する

ShortNotes アプリケーションのスキーマを設計するための 2 つ目の手法は、Notebook 用のコレクションと Note 用のコレクションに分けて、コレクションに含めるそれぞれの Note ドキュメントに Notebook ドキュメントへの参照を持たせるというものです。この手法は RDBMS パラダイムに近づくことになるため、MongoDB のスキーマ設計に反するように思えるかもしれません。それでも状況によっては推奨される手法の 1 つとなります。ここでポイントとなるのは、いずれかの手法を使用するように強制されてはいないことです。スキーマ設計は、それぞれのアプリケーションの状況に応じたものにする必要があります。Notebook は、数個のフィールドがあるだけの極めて単純なドキュメントなので、各 Note ドキュメントに Notebook ID だけでなく、Notebook ドキュメントを含めるという方法が考えられます。こうすれば、コレクション間の相互作用が必要なくなり、クエリーが単純になります。リスト 15 に Notebook ドキュメントを記載します。

リスト 15. 単純な Notebook ドキュメントの例
{ 
    "name" : "MongoDB Notebook", 
    "author" : "shekhar", 
    "created" : ISODate("2012-04-07T09:36:01.062Z") 
}

リスト 16 に、「MongoDB Notebook」という名前のメモ帳に含まれるメモ (Note ドキュメント) の例を記載します。

リスト 16. Note ドキュメントの例
{ 
    "_id" : ObjectId("4f800b5cc2fceff338eb9a87"), 
    "title" : "Getting Started with MongoDB", 
    "note" : "Getting Started with MongoDB", 
    "created" : ISODate("2012-04-07T09:38:42.462Z"), 
    "notebook" : { 
        "_id" : ObjectId("4f800af3c2fceff338eb9a86"), 
        "name" : "MongoDB Notebook", 
        "author" : "shekhar", 
        "created" : ISODate("2012-04-07T09:36:01.062Z") 
    } 
}

この設計では、Notes コレクションと Notebooks コレクションの両方に対して簡単にクエリーを実行することができます。「MongoDB Notebook」という名前のメモ帳に含まれるすべてのメモを検索するには、 db.notes.findOne({"notebook.name":"MongoDB Notebook"}) というクエリーを作成します。

また、 db.notes.ensureIndex({"notebook.name":1}) のように、notebook.name で索引を作成して、クエリーの読み取りを非常に高速化に行えるようにすることもできます。

このスキーマ設計には 1 つの問題があります。それは、Notebooks コレクション内のドキュメントを変更する場合には、Notes コレクション内の対応する参照を手動で変更しなければならないことです。

このサンプル・アプリケーションには、Notes と Notebooks の個別のコレクションを使用するリレーショナル手法を適用します。


Spring Roo のインストール

アプリケーションの作成に取り掛かる前に、お使いのマシンに Spring Roo 1.2.1 がインストールされていることを確認してください。スタンドアロンの Spring Roo をインストールする場合は、以下の手順に従います。

  1. Roo のスタンドアロンのコマンドライン・シェルをダウンロードするか、Roo に組み込まれている STS (SpringSource Tool Suite) プラグイン (「参考文献」を参照) を使用します。STS には Spring 対応 Eclipse ベースのアプリケーションよりも多くの機能が用意されているため、両方ともダウンロードして、一緒に使用することをお勧めします。

  2. Spring Roo を任意のディレクトリーに解凍します。

  3. 環境変数を設定します。

    1. Windows マシンでは、%ROO_HOME%\bin をパスに追加します。ここで、ROO_HOME は、解凍後の Roo ファイルへのパスです。

    2. *nix マシンでは、$ROO_HOME/bin/roo.sh へのシンボリック・リンクを作成します (例: sudo ln -s ~/spring-roo-1.x.x/bin/roo.sh /usr/bin/roo)。


Spring Roo を使用して ShortNotes アプリケーションを作成する方法

Spring Roo は稼働状態になったので、アプリケーションの作成を開始します。以下の手順に従って、ShortNotes アプリケーションを作成してください。

  1. オペレーティング・システムのコマンドライン・シェルを開き、mkdir コマンドを使用して shortnotes という名前のディレクトリーを作成します。

  2. カレント・ディレクトリーを shortnotes に変更して、「roo」(または「roo.sh」) と入力し、Enter キーを押します。これで、Roo シェルがロードされます。

  3. まず、以下の project コマンドを使用して、Roo シェル内でプロジェクトを作成します。

    project --topLevelPackage com.xebia.shortnotes --projectName shortnotes

    このproject コマンドによって、Spring Maven テンプレート・プロジェクトが作成されます。このコマンドによって生成される主要な成果物は、pom.xml ファイルと applicationContext.xml ファイルです。pom.xml には、必要なすべての Spring jar ファイルと、さまざまな maven プラグイン、そしてリポジトリーの宣言が含まれることになります。applicationContext.xml ファイルは汎用的な Spring コンテキスト・ファイルです。個々のコンポーネントは com.xebia.shortnotes パッケージでこのファイルをスキャンするため、Spring は @Component@Service、および @Repository アノテーションが設定されたクラスをすべて見つけることができます。コンポーネント・スキャンでは、@Controller アノテーションの付いたすべてのクラスが実行されます。これらのクラスは、Web アプリケーション・コンテキストによってロードされるためです。

  4. 次の論理アクションを提示する hint コマンドを入力します。すると、jpa のセットアップまたは mongo のセットアップのいずれかを行うようにアドバイスしてくるはずです。ここでは MongoDB バックエンドに使用したアプリケーションを作成するので、以下の mongo setup コマンドを使用します。

    mongo setup --databaseName shortnotes --host localhost --port 27017

    mongo setup コマンドに必須の属性はありませんが、この例では databaseNamehost、および port 属性を指定しました。このコマンドで属性を指定しない場合、Spring Roo はデフォルトの値を挿入しますが、それらの値は上記で指定した値と同じになります。指定できるその他の属性には、 usernamepasswordcloudfoundry の 3 つがあります。usernamepassword は、データストアが認証情報を要求する場合、MongoDB にアクセスするために使用されます。cloudfoundry 属性は、cloudfoundry PaaS にアプリケーションをデプロイする場合に使用されます。これについては、後ほど説明します。

    mongo setup コマンドは、以下の 3 つの処理を行います。

    • 必要な依存関係を pom.xml に追加します。
    • 新規 Spring コンテキスト・ファイルとして applicationContext-mongo.xml を作成します。
    • database.properties ファイルを作成します。

    このコマンドによって追加される依存関係は、Spring MongoDB と Bean 検証をサポートするためのものです。database.properties ファイルには、hostportdatabaseName などのプロパティーが格納されます。最も重要な情報を格納するのは、applicationContext-mongo.xml ファイルです。このファイルは mongo 名前空間を利用するため、Spring Beans 宣言を作成する必要はありません。したがって、開発者の作業が大幅に容易になります。リスト 17 に記載する applicationContext-mongo.xml のスニペットを参照してください。

    リスト 17. applicationContext-mongo.xml の例
    <mongo:db-factory dbname="${mongo.database}" host="${mongo.host}" -----> (1) 
    id="mongoDbFactory" port="${mongo.port}"/> 
    
    <mongo:repositories base-package="com.xebia.shortnotes"/> -------------> (2)
    
    <context:annotation-config/> ------------------------------------------> (3)
    
    <bean ----->(4) id="mongoTemplate"> 
    
        <constructor-arg ref="mongoDbFactory"/> 
    
    </bean>

    applicationContext-mongo.xml には小さなバグがあります。そのバグというのは、dbnamemongo.database というプロパティーに対応するものの、このプロパティーは database.properties ファイルに存在しないことです。そのため、mongo.databasemongo.name で置き換える必要があります。以下に、リスト 17 の XML スニペットで宣言されている 4 つの行 (1) から (4) について説明します。

    1. 行 (1) で作成するファクトリーは、localhost のポート 27017 で稼働する shortnotes という名前の MongoDB データベースに接続する Mongo インスタンスを生成します。この宣言でも、認証のための username および password を指定することができます。上記の宣言には示されていませんが、もう 1 つの重要かつ便利な属性は、記事の最初で説明した WriteConcern です。この属性を使用して、書き込み動作を変更することができます。デフォルト値は、none です。この値は「ファイア・アンド・フォーゲット」を指定するため、データを損失する可能性があります。

    2. 行 (2) は、MongoRepository インターフェースや、com.xebia.shortnotes パッケージに含まれるそのスーパータイプのいずれかを継承するインターフェースのすべてが、確実に Spring リポジトリー Bean を持つようにします。リポジトリー実装 Bean は動的に作成され、CRUD とページネーションのサポートが含められます。これにより、開発者の作業が大幅に軽減され、CRUD およびページネーション・メソッドに関連するボイラープレート・コードの多くが取り除かれます。さらに、何らかの規約に従って CRUD メソッドと finder メソッドを生成することもできます。例えば、このアプリケーションで作成者のすべてのメモ帳を検索するには、以下に示すメソッドを宣言します。すると、その実装が実行時に生成されます。詳細については Spring MonboDB のドキュメント (「参考文献」を参照) を参照してください。

       public List<Notebook> findByAuthor(String author)
    3. 行 (3) は、RuntimeException を、Spring 例外階層の該当する例外に変換するために使用されます。

    4. 最後の行 (4) は、createdeletefind、および update といった操作をその他の有用な各種メソッドと一緒に実行するために使用できる MongoTemplate Bean を作成します。また、ドメイン・オブジェクトと MongoDB ドキュメントとの間のマッピングも行います。リポジトリーで実行する操作はすべて MongoTemplate で実行することができますが、その逆は当てはまりません。MongoTemplate は、Spring MongoDB サポートの最も重要なクラスです。MongoTemplate クラスで公開されるメソッドは、MongoDB コマンドライン・クライアントで実行するメソッドと密接に対応します。MongoTemplate クラスは、Query API と Criteria API を利用してクエリーを作成します。このアプリケーションの例で作成者のすべてのメモ帳を検索するには、以下の内容を入力します。

      List<Notebook> myNotebooks = 
           mongoTemplate.find(Query.query(Criteria.where("author").is
                     ("shekhar")),Notebook.class)
  5. MongoDB をセットアップした後は、Notebook エンティティーと Note エンティティーを作成します。それには、リスト 18 の entity mongo コマンドを使用します。

    リスト 18. エンティティーを作成する
     entity mongo --class ~.domain.Notebook --testAutomatically 
     entity mongo --class ~.domain.Note --testAutomatically

    リスト 18 の 2 つのコマンドは、Notebook.java および Note.java と併せて、ITD とテスト・インフラストラクチャー・コードを作成します。testAutomatically 属性の役割は、それぞれのドメイン・クラスの結合テストを作成することです。entity mongo コマンドによって生成される重要な成果物には、Notebook_Roo_Mongo_Entity.aj と Note_Roo_Mongo_Entity.aj があります。これらの ITD は、エンティティーに @Persistent アノテーションを設定すること、そして id の型を BigInteger にすることを指定します。Spring MongoDB は BigInteger 型の idObjectId に変換してから永続化します。残りの成果物は、エンティティー・フィールドのゲッターおよびセッターと、toString() メソッドを指定するためのものです。

  6. エンティティーを作成したら、次に field コマンドを使ってエンティティーにフィールドを追加します。まずは、リスト 19 のコマンドを使用して Notebook エンティティーにフィールドを追加してください。
    リスト 19. Notebook のフィールドを作成する
    focus --class ~.domain.Notebook 
    field string --fieldName name --notNull 
    field string --fieldName author --notNull 
    field date --fieldName created --type java.util.Date --notNull

    今度は、リスト 20 のコマンドで Note エンティティーにフィールドを追加します。

    リスト 20. Note のフィールドを作成する
    focus --class ~.domain.Note 
    field string --fieldName title --notNull 
    field string --fieldName content --notNull --sizeMax 4000 
    field date --fieldName created --type java.util.Date --notNull

    リスト 20 のコマンドで興味深い点は、両方のエンティティーに作成されるフィールド名によって、フィールドが更新不可能になることです。これは、これらのエンティティーのユーザー・インターフェースの基礎を生成するときに、作成済みフィールドを編集できないことを意味します。

  7. これまでの作業で作成したドメイン・モデルは、まだ完成していません。Notebook と Note との間の関係を定義していないためです。スキーマ設計のセクションで説明したように、各 Note ドキュメントには、Notebook ドキュメントが組み込まれます。つまり、メモ帳に 100 個のメモが含まれているとすると、Notebook コレクションには 1 つのオリジナルの Notebook ドキュメントが含まれ、100 個の Note ドキュメントのそれぞれに Notebook ドキュメントのコピーが含まれることになります。けれども、このスキーマ設計のほうが単純で、この場合の要件をより適切に満たしています。”notebook” フィールドを Note エンティティーに追加するには、以下のコマンドを入力します。

    field reference --type ~.domain.Notebook --fieldName notebook --notNull

    このコマンドにより、既存の Notebook がある場合にのみ、Note が作成されることが確実になります。

  8. これでドメイン・モデルが完成したので、今度は前に作成したエンティティーのリポジトリーを作成することができます。リポジトリーは、Spring MongoDB サポートによって提供されます。Notebook エンティティーのリポジトリーを作成するには、リスト 21 のコマンドを実行します。このリストには、出力例も記載されています。

    リスト 21. リポジトリーの作成による出力例
    repository mongo --interface ~.repository.NotebookRepository 
                   --entity ~.domain.Notebook
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/repository
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/repository/NotebookRepository.java
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/repository/
                   NotebookRepository_Roo_Mongo_Repository.aj

    上記の出力には、リポジトリー・フォルダー、Java ファイル、ITD が作成されたことが示されています。すべての Notebook エンティティーを検索するための findAll() メソッドが含まれる NotebookRepository.java ファイルには、@RooMongoRepository でアノテーションが付けられます。これは Roo に対し、NotebookRepository_Roo_Mongo_Repository.aj ITD ファイルを生成するように指示するためです。コンパイル時には、ITD のコードがインターフェースにプッシュされます。この ITD が、すべてのコードが含まれる場所です。リスト 22 に、Spring Roo によって生成された ITD ファイルを記載します。

    リスト 22. ITD ファイルの例
    privileged aspect NotebookRepository_Roo_Mongo_Repository { 
        declare parents: NotebookRepository extends 
            PagingAndSortingRepository<Notebook, BigInteger>; 
        declare @type: NotebookRepository: @Repository; 
    }

    上記の ITD は、NoteBookRepository インターフェースに @Repository アノテーションを付けること、そしてこの NoteBookRepository インターフェースは PagingAndSortingRepository インターフェースを継承する必要があることを定義しています。したがって、NotebookRepository インターフェースがコンパイルされると、このインターフェースは @Repository アノテーションが付けられ、PagingAndSortingRepository を継承することになります。ステップ 4 で説明したように、リポジトリー実装は実行時に作成されます。PagingAndSortingRepository インターフェースを実装することから、CRUD メソッドと、ページネーションとソートを使用してエンティティーを検索するその他のメソッドを使用できるようになります。

    Note エンティティーのリポジトリーも、Notebook の場合と同じようなコマンドによって作成することができます。

    repository mongo --interface ~.repository.NoteRepository --entity ~.domain.Note
  9. 次に、Notebook および Note エンティティーに対応するサービス層を追加します。このサービス層は、コントローラー層とリポジトリー層との間のファサードとして機能します。アプリケーションに固有のビジネス・ロジックは、このサービス層に含めることができます。リスト 23 に、Notebook エンティティーに対する service コマンドと、このコマンドによる出力を記載します。

    リスト 23. Notebook エンティティーに対する service コマンドの出力例
    service --interface ~.service.NotebookService --entity ~.domain.Notebook
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/service
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/service/NotebookService.java
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/service/NotebookServiceImpl.java
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/service/NotebookService_Roo_Service.aj
    Created SRC_MAIN_JAVA/com/xebia/shortnotes/service/NotebookServiceImpl_Roo_Service.aj

    同じようなコマンド service --interface ~.service.NoteService --entity ~.domain.Note によって、Note エンティティーのサービス層を作成することができます。

  10. 最後に、リスト 24web mvc コマンドを使用して、このサンプル・アプリケーションの Spring MVC コントローラーを作成することができます。

    リスト 24. web mvc コマンドの例
    web mvc setup 
    web mvc all --package ~.web

    web mvc setup コマンドは、Spring MVC に必要なインフラストラクチャーをセットアップするために、pom.xml に Spring MVC 依存関係を追加し、webmvc-config.xml という名前の Web アプリケーション・コンテキスト・ファイルを作成し、タグ・ライブラリーを生成し、国際化対応をセットアップするという一連の処理を行います。続いて web mvc all コマンドがコントローラー・クラスを作成し、それに対応するビューを生成します。

  11. Roo シェルを終了します。

  12. mongod 実行可能ファイルを使用して MongoDB サーバーを起動します。

  13. アプリケーションを実行するには、「mvn tomcat:run」と入力します。これによって、tomcat サーバーが起動されます。次に、Web ブラウザーを開いて、http://localhost:8080/shortnotes/ にアクセスします。メモ帳を作成した後、どのメモ帳を使用するかを指定してメモを作成することができます。私はサンプルとして、名前 (“name”) を “MongoDB Notes“ に、作成者 (“author”) を “shekhar“ に設定したメモ帳を作成しました。続いて、タイトル (“titel”) とコンテンツ (“content”) の両方を “Getting Started with MongoDB“ に指定したメモを作成し、それを作成済みのメモ帳に割り当てました。リスト 25 に、この Notebook ドキュメントと Note ドキュメントを記載します。

    リスト 25. Notebook ドキュメントおよび Note ドキュメントのサンプル
    {
        "_id" : ObjectId("4f808ee084aeed43f24b692b"),
        "_class" : "com.xebia.shortnotes.domain.Notebook", 
        "name" : "MongoDB Notes", 
        "author" : "shekhar", 
        "created" : ISODate("2012-04-07T19:00:48.386Z") 
    }
    
    {
        "_id" : ObjectId("4f808ef184aeed43f24b692c"), 
        "_class" : "com.xebia.shortnotes.domain.Note", 
        "title" : "Getting Started with MongoDB", 
        "content" : "Getting Started with MongoDB", 
        "created" : ISODate("2012-04-07T19:01:05.031Z"),
        "notebook" : { 
            "_id" : ObjectId("4f808ee084aeed43f24b692b"), 
            "name" : "MongoDB Notes", 
            "author" : "shekhar", 
            "created" : ISODate("2012-04-07T19:00:48.386Z")
        } 
    }
  14. 例えば、Notebook の名前を “MongoDB Cookbook” に変更すると、この Notebook ドキュメントが含まれる Note ドキュメントは更新されないことがわかるでしょう。これは、予想されていた動作です。この問題を修正するには、Notebook ドキュメントを更新した後、すべての Note ドキュメントを更新する必要があります。そこで、NoteServiceImpl に、リスト 26 に記載する updateNotesWithNotebook メソッドを新たに作成してください。

    リスト 26. updateNotesWithNotebook メソッドを作成する
    @Autowired 
    MongoTemplate mongoTemplate; 
    	 
    public void updateNotesWithNoteBook(Notebook notebook){ 
        Update update = new Update().set("notebook.name", 
        notebook.getName()).set("notebook.author", notebook.getAuthor()); 
    
    Query query = Query.query(Criteria.where("notebook._id").is(new 	
        ObjectId(notebook.getId().toString(16)))); 
            mongoTemplate.updateMulti(query, update, Note.class);

    リスト 26 のコードは、更新された Notebook に対応するすべてのドキュメントを更新するために、MongoDBTemplateupdateMulti メソッドを使用します。updateMulti() メソッドが取る引数は、 クエリー・オブジェクト更新オブジェクトコレクション・エンティティー・タイプの 3 つです。クエリー・オブジェクトで、指定された id が設定された Notebook を持つすべての Note ドキュメントを選択するように指定します。次に、Notebook の作成者と名前を設定するための更新オブジェクトを作成します。

    updateNotesWithNotebook メソッドを作成したら、NotebookController 内で Notebook を更新した後、このメソッドを呼び出してください (リスト 27 を参照)。update メソッドは必ず ITD から NotebookController Java クラスにプッシュするようにしてください。

    リスト 27. ITD から更新をプッシュする例
    @Autowired 
    private NoteService noteService; 
    
    @RequestMapping(method = RequestMethod.PUT, produces = "text/html") 
    public String update(@Valid Notebook notebook, BindingResult bindingResult, 
    Model uiModel, HttpServletRequest httpServletRequest) { 
    
            if (bindingResult.hasErrors()) { 
                populateEditForm(uiModel, notebook); 
                return "notebooks/update"; 
            } 
            uiModel.asMap().clear(); 
            notebookService.updateNotebook(notebook); 
            noteService.updateNotesWithNoteBook(notebook); 
            return "redirect:/notebooks/" + 	
                encodeUrlPathSegment(notebook.getId().toString(), httpServletRequest); 
     }
  15. 同じ問題は、Notebook ドキュメントを削除する場合にも起こります。Note ドキュメントには、削除された Notebook への参照が残っているためです。Notebook ドキュメントが削除された場合は、その特定の Notebook ドキュメントのすべての Note ドキュメントを削除するのが当然です。それには、NoteServiceImpl クラスに、リスト 28 に記載する removeNotes() メソッドを追加します。

    リスト 28. removeNotes() メソッドの例
    public void removeNotes(Notebook notebook){ 
        mongoTemplate.remove(Query.query(Criteria.where("notebook._id").is(new
            ObjectId(notebook.getId().toString(16)))), Note.class);
    }

    removeNotes() メソッドは、Notebook ドキュメントが削除されると呼び出されます。NotebookController の delete() メソッドの中に、リスト 29 に記載する removeNotes 呼び出しを追加します。

    リスト 29. NotebookController に removeNotes を追加する
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE,
            produces = "text/html")
    public String delete(@PathVariable("id") BigInteger id,
            @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "size", required = false) Integer size,
            Model uiModel) {
    Notebook notebook = notebookService.findNotebook(id);
    
    noteService.removeNotes(notebook);
    notebookService.deleteNotebook(notebook);
    uiModel.asMap().clear();
    uiModel.addAttribute("page", (page == null) ? "1" :
        page.toString());
    uiModel.addAttribute("size", (size == null) ? "10" :
        size.toString());
    return "redirect:/notebooks";
    }

    mvn tomcat:run によってアプリケーションを再度実行し、Notebook ドキュメントを作成した後、Note ドキュメントを作成し、最後に Notebook ドキュメントを更新すると、今度は Note ドキュメントの Notebook ドキュメントも更新されることが確認できるはずです。また、Notebook ドキュメントを削除すると、その Notebook ドキュメントを対象とするすべての Note ドキュメントも削除されます。

Cloud Foundry にデプロイする

ShortNotes アプリケーションの作成は完了しました。次の作業は当然、このアプリケーションをデプロイすることです。Spring アプリケーションを Cloud Foundry パブリック・クラウドにデプロイするために、アプリケーションに必要な変更は何もありません。Cloud Foundry に馴染みがないという方は、第 4 回第 6 回で詳しく説明しているので、この 2 つの記事を参照してください。今回の記事では vmc ruby gem によってカンファレンス・アプリケーションを Cloud Foundry にデプロイします。以下の手順に従ってください。

  1. mongo setup コマンドをもう一度実行する必要があるので、Roo シェルを再び起動してください。今回は、cloud foundry MongoDB インスタンスに切り替えます。Roo シェルで以下のコマンドを実行して、applicationContext-mongo.xml を更新します。

    mongo setup --cloudFoundry
  2. お使いのマシンに vmc クライアントをインストールします (コマンドライン・インターフェースのインストール方法をステップバイステップで説明しているチュートリアルについては、「参考文献」を参照してください)。

  3. Cloud Foundry に登録したクレデンシャルを使用して、Cloud Foundry パブリック・クラウドにログインします。vmc login コマンドを入力すると、e-メールとパスワードを入力するように指示されます (リスト 30 を参照)。

    リスト 30. vmc から Cloud Foundry にログインする
    shekhar@shekhar:~/dev/writing/shortnotes/target$ vmc login 
    Attempting login to [http://api.cloudfoundry.com] 
    Email: shekhargulati84@gmail.com 
    Password: ************* 
    Successfully logged into [http://api.cloudfoundry.com]
  4. vmc クライアントをインストールした後、ShortNotes アプリケーションの Maven ビルドを行う必要があります。「mvn clean install」と入力します。

  5. プロジェクトをビルドしたら、アプリケーションを Cloud Foundry にプッシュします。コマンドラインからコードをプッシュするには、カレント・ディレクトリーをターゲット・フォルダーに変更して、vmc push コマンドを入力します。vmc push コマンドからの質問には、リスト 31 に示すように答えます。

    リスト 31. vmc を使用してアプリケーションを Cloud Foundry にプッシュする
    shekhar@shekhar:~/dev/writing/dw/shortnotes/target$ vmc push 
    Would you like to deploy from the current directory? [Yn]: Y 
    Application Name: shortnotes 
    Application Deployed URL [shortnotes.cloudfoundry.com]: 
    Detected a Java SpringSource Spring Application, is this correct? [Yn]: Y 
    Memory Reservation (64M, 128M, 256M, 512M, 1G) [512M]: 
    Creating Application: OK 
    Would you like to bind any services to 'shortnotes'? [yN]: y 
    Would you like to use an existing provisioned service? [yN]: N 
    The following system services are available 
    1: mongodb 
    
    2: mysql 
    3: postgresql 
    4: rabbitmq 
    5: redis 
    Please select one you wish to provision: 1 
    Specify the name of the service [mongodb-484f6]: 
    Creating Service: OK 
    Binding Service [mongodb-484f6]: OK 
    Uploading Application: 
      Checking for available resources: OK 
      Processing resources: OK 
      Packing application: OK 
      Uploading (85K): OK   
    Push Status: OK 
    Staging Application: OK                                                         
    Starting Application: OK
  6. 最後に、http://shortnotes.cloudfoundry.com/ にアクセスすると、クラウド内で実行中の ShortNotes アプリケーションを確認することができます。

ShortNotes アプリケーションのソース・コードを入手するには、shortnotes github リポジトリー (「参考文献」を参照) を複製してください。


まとめ

この記事では、MongoDB について紹介し、Spring Roo を使って Spring MongoDB アプリケーションを構築する方法を説明しました。そのなかで、MongoDB の基本操作、要件に最適なスキーマを選択する方法、そして Spring MongoDB アプリケーションを素早く構築する上で、Spring Roo がどのように役立つかを説明しました。

今回の記事では、MongoDB MapReduce、配列修飾子、MongoDB レプリケーションのセットアップ、地理空間のクエリーなどの機能については取り上げませんでした。その他にも、探るべき機能はたくさんあります。「参考文献」に記載されているドキュメントのなかに、参考になるリソースが見つかるはずです。

参考文献

学ぶために

製品や技術を入手するために

  • プロジェクト Web サイトから MongoDB をダウンロードしてください。
  • Spring Roo をダウンロードしてください。
  • SpringSource Tool Suite をダウンロードしてください。
  • Spring Roo Webサイトから Spring Roo を入手してください。
  • ShortNotes アプリケーションのソース・コードを入手するには、shortnotes github リポジトリーを複製してください。
  • IBM 試用版ソフトウェアを使用して、開発者専用のソフトウェアを使って次のオープンソース開発プロジェクトを革新してください。IBM 試用版ソフトウェアは、ダウンロードまたは DVD で入手できます。

議論するために

  • 他の developerWorks ユーザーとのつながりを持つと同時に、開発者によるブログ、フォーラム、グループ、ウィキを調べてください。developerWorks コミュニティーで、Real world open source グループの構築を手伝ってください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Java technology, Linux
ArticleID=838122
ArticleTitle=Spring Roo 入門: 第 7 回 Spring Roo を使って Spring MongoDB アプリケーションを開発する
publish-date=10042012