1. 概要

このチュートリアルでは、JavaでMongoDBのオブジェクトドキュメントマッパー(ODM)であるMorphiaを使用する方法を理解します。

その過程で、ODMとは何か、そしてそれがMongoDBでの作業をどのように促進するかについても理解します。

2. ODM とは何ですか?

この分野に慣れていない人のために、 MongoDBは、自然に配布されるように構築されたドキュメント指向のデータベースです。 ドキュメント指向データベースは、簡単に言えば、ドキュメントを管理します。ドキュメントは、半構造化データを整理するスキーマレスの方法に他なりません。 これらは、SQLデータベースの従来の編成からの明らかな逸脱にちなんで名付けられた、より広く大まかに定義されたNoSQLデータベースの傘下にあります。

MongoDBは、Javaのようなほとんどすべての一般的なプログラミング言語用のドライバーを提供します。 これらのドライバーは、MongoDBを操作するための抽象化レイヤーを提供するため、WireProtocolを直接操作することはありません。 これは、Oracleがリレーショナルデータベース用のJDBCドライバーの実装を提供していると考えてください。

ただし、JDBCを直接使用していた日々を思い出すと、特にオブジェクト指向のパラダイムでは、JDBCがいかに厄介になるかを理解できます。 幸い、Hibernateのようなオブジェクトリレーショナルマッピング(ORM)フレームワークがあります。 MongoDBでもそれほど違いはありません。

確かに低レベルのドライバーで作業することはできますが、タスクを実行するにはさらに多くの定型文が必要です。 ここでは、 Object Document Mapper(ODM)と呼ばれるORMと同様の概念があります。 Morphiaは、Javaプログラミング言語のスペースを正確に埋め、MongoDBのJavaドライバーの上で動作します。

3. 依存関係の設定

いくつかのコードに入るのに十分な理論を見てきました。 この例では、本のライブラリをモデル化し、Morphiaを使用してMongoDBでそれを管理する方法を確認します。

ただし、始める前に、いくつかの依存関係を設定する必要があります。

3.1. MongoDB

動作させるには、MongoDBの実行中のインスタンスが必要です。 これを取得するにはいくつかの方法がありますが、最も簡単な方法は、ローカルマシンにコミュニティエディションをダウンロードしてインストールすることです。

MongoDBが実行されるポートを含め、すべてのデフォルト構成をそのままにしておく必要があります。

3.2. モルヒネ

Morphia用にビルド済みのJARをMavenCentral からダウンロードして、Javaプロジェクトで使用できます。

ただし、最も簡単な方法は、Mavenのような依存関係管理ツールを使用することです。

<dependency>
    <groupId>dev.morphia.morphia</groupId>
    <artifactId>core</artifactId>
    <version>1.5.3</version>
</dependency>

4. Morphiaを使用して接続する方法は?

これで、MongoDBがインストールおよび実行され、JavaプロジェクトでMorphiaがセットアップされたので、Morphiaを使用してMongoDBに接続する準備が整いました。

それをどのように達成できるか見てみましょう。

Morphia morphia = new Morphia();
morphia.mapPackage("com.baeldung.morphia");
Datastore datastore = morphia.createDatastore(new MongoClient(), "library");
datastore.ensureIndexes();

それはほとんどそれです! これをもっとよく理解しましょう。 マッピング操作を機能させるには、次の2つが必要です。

  1. マッパー:これは、JavaPOJOをMongoDBコレクションマッピングする役割を果たします。 上記のコードスニペットでは、Morphiaがその責任を負うクラスです。 POJOを検索するパッケージをどのように構成しているかに注意してください。
  2. 接続:これは、マッパーがさまざまな操作を実行できるMongoDBデータベースへの接続です。 クラスDatastoreは、 MongoClient (Java MongoDBドライバーから)のインスタンスとMongoDBデータベースの名前をパラメーターとして受け取り、はアクティブな接続を返します[X202X ]。

したがって、このデータストアを使用して、エンティティを操作する準備が整いました。

5. エンティティを操作する方法は?

新しく作成したDatastoreを使用する前に、操作するドメインエンティティをいくつか定義する必要があります。

5.1. 単純なエンティティ

いくつかの属性を持つ単純なBookエンティティを定義することから始めましょう。

@Entity("Books")
public class Book {
    @Id
    private String isbn;
    private String title;
    private String author;
    @Property("price")
    private double cost;
    // constructors, getters, setters and hashCode, equals, toString implementations
}

ここで注意すべき興味深い点がいくつかあります。

  • MorphiaによるODMマッピングに対してこのPOJOを修飾する注釈@Entityに注目してください。
  • Morphiaは、デフォルトで、エンティティをそのクラスの名前でMongoDBのコレクションにマップしますが、これを明示的にオーバーライドできます(ここでエンティティ Book に対して行ったように)
  • Morphiaは、デフォルトで、エンティティ内の変数を変数の名前でMongoDBコレクション内のキーにマップしますが、これもオーバーライドできます(ここで変数 cost に対して行ったように)
  • 最後に、アノテーション@Id によって主キーとして機能するエンティティ内の変数をマークする必要があります(ここで本にISBNを使用しているように)

5.2. 関係のあるエンティティ

ただし、現実の世界では、エンティティは見た目ほど単純ではなく、相互に複雑な関係を持っています。 たとえば、単純なエンティティ Book は、 Publisher を持つことができ、他のコンパニオンブックを参照できます。 それらをどのようにモデル化しますか?

MongoDBは、関係を構築するための 2つのメカニズム(参照と埋め込み)を提供します。 名前が示すように、参照すると、MongoDBは関連データを別のドキュメントとして同じまたは異なるコレクションに格納し、そのIDを使用して参照します。

逆に、埋め込みを使用すると、MongoDBはリレーションを保存するか、親ドキュメント自体に埋め込みます。

それらの使い方を見てみましょう。 出版社に埋め込むことから始めましょう。

@Embedded
private Publisher publisher;

十分に単純です。 それでは、先に進んで他の本への参照を追加しましょう。

@Reference
private List<Book> companionBooks;

それだけです— Morphiaは、MongoDBでサポートされているように、モデルの関係に便利な注釈を提供します。 ただし、参照と埋め込みの選択は、他の考慮事項の中でも特に、データモデルの複雑さ、冗長性、および一貫性から引き出す必要があります。

この演習は、リレーショナルデータベースの正規化に似ています。

これで、データストアを使用してブックでいくつかの操作を実行する準備が整いました。

6. いくつかの基本的な操作

Morphiaを使用していくつかの基本的な操作を操作する方法を見てみましょう。

6.1. 保存

最も単純な操作から始めましょう。MongoDBデータベースライブラリBookのインスタンスを作成します。

Publisher publisher = new Publisher(new ObjectId(), "Awsome Publisher");

Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher);
Book companionBook = new Book("9789332575103", "Java Performance Companion", 
  "Tom Kirkman", 1.95, publisher);

book.addCompanionBooks(companionBook);

datastore.save(companionBook);
datastore.save(book);

これは、MorphiaがMongoDBデータベースにコレクションを作成し、存在しない場合はアップサート操作を実行するのに十分です。

6.2. クエリ

MongoDBで作成したばかりの本をクエリできるかどうかを見てみましょう。

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(1, books.size());

assertEquals(book, books.get(0));

Morphiaでのドキュメントのクエリは、 Datastore を使用してクエリを作成し、関数型プログラミングを愛する人を喜ばせるために、宣言的にフィルターを追加することから始まります。

Morphiaは、フィルターと演算子を使用した複雑なクエリ構築をはるかにサポートしています。 さらに、Morphiaでは、クエリ内の結果の制限、スキップ、および順序付けが可能です。

さらに、Morphiaを使用すると、必要に応じて、MongoDBのJavaドライバーで記述された生のクエリを使用してより詳細な制御を行うことができます。

6.3. アップデート

主キーが一致する場合、保存操作で更新を処理できますが、Morphiaはドキュメントを選択的に更新する方法を提供します。

Query<Book> query = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java");

UpdateOperations<Book> updates = datastore.createUpdateOperations(Book.class)
  .inc("price", 1);

datastore.update(query, updates);

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(4.95, books.get(0).getCost());

ここでは、クエリと更新操作を作成して、クエリによって返されるすべての本の価格を1つ上げます。

6.4. 消去

最後に、作成されたものを削除する必要があります! 繰り返しになりますが、Morphiaを使用すると、非常に直感的です。

Query<Book> query = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java");

datastore.delete(query);

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(0, books.size());

以前とまったく同じようにクエリを作成し、Datastoreで削除操作を実行します。

7. 高度な使用法

MongoDBには、集計、インデックス作成、その他多くのなどの高度な操作があります。 Morphiaを使用してすべてを実行することはできませんが、その一部を実行することは確かに可能です。 他の人にとっては、悲しいことに、MongoDBのJavaドライバーにフォールバックする必要があります。

Morphiaを介して実行できるこれらの高度な操作のいくつかに焦点を当てましょう。

7.1. 集約

MongoDBでの集約により、一連のドキュメントを操作して集約された出力を生成できるパイプラインで一連の操作を定義できます

Morphiaには、このような集約パイプラインをサポートするAPIがあります。

すべての本が著者によってグループ化されるような方法で図書館データを集約したいとします。

Iterator<Author> iterator = datastore.createAggregation(Book.class)
  .group("author", grouping("books", push("title")))
  .out(Author.class);

では、これはどのように機能しますか? 同じ古いデータストアを使用して集約パイプラインを作成することから始めます。 ここでは、 Book など、集計操作を実行するエンティティを提供する必要があります。

次に、ドキュメントを「作成者」ごとにグループ化し、「本」というキーの下に「タイトル」を集約します。 最後に、ここではODMを使用しています。 したがって、集約されたデータを収集するエンティティを定義する必要があります。この場合は、Authorです。

もちろん、booksという変数を使用してAuthorというエンティティを定義する必要があります。

@Entity
public class Author {
    @Id
    private String name;
    private List<String> books;
    // other necessary getters and setters
}

もちろん、これはMongoDBによって提供される非常に強力な構造の表面を引っかいただけであり、詳細についてはさらに詳しく調べることができます

7.2. 投影

MongoDBでのプロジェクションを使用すると、クエリでドキュメントからフェッチするフィールドのみを選択できます。 ドキュメントの構造が複雑で重い場合、これは、必要なフィールドが少ない場合に非常に役立ちます。

クエリでタイトルのある本だけを取得する必要があるとしましょう。

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .project("title", true)
  .find()
  .toList();
 
assertEquals("Learning Java", books.get(0).getTitle());
assertNull(books.get(0).getAuthor());

ここでは、ご覧のとおり、結果のタイトルのみが返され、著者やその他のフィールドは返されません。 ただし、MongoDBに保存する際に、投影された出力を使用する場合は注意が必要です。 これにより、データが失われる可能性があります。

7.3. インデックス作成

インデックスは、データベースを使用したクエリの最適化において非常に重要な役割を果たします。リレーショナルデータベースだけでなく、多くの非リレーショナルデータベースも同様です。

MongoDB は、デフォルトで主キーに作成された一意のインデックスを使用して、コレクションのレベルでインデックスを定義します。 さらに、MongoDBを使用すると、ドキュメント内の任意のフィールドまたはサブフィールドにインデックスを作成できます。 作成するクエリに応じて、キーにインデックスを作成することを選択する必要があります。

たとえば、この例では、 Book のフィールド「title」にインデックスを作成したい場合があります。これは、多くの場合、クエリを実行するためです。

@Indexes({
  @Index(
    fields = @Field("title"),
    options = @IndexOptions(name = "book_title")
  )
})
public class Book {
    // ...
    @Property
    private String title;
    // ...
}

もちろん、追加のインデックスオプションを渡して、作成されるインデックスのニュアンスを調整することもできます。 インデックスで使用するには、フィールドに@ Propertyという注釈を付ける必要があることに注意してください。

さらに、クラスレベルのインデックスとは別に、Morphiaにはフィールドレベルのインデックスを定義するためのアノテーションもあります。

7.4. スキーマ検証

更新または挿入操作の実行中にMongoDBが使用できるコレクションのデータ検証ルールを提供するオプションがあります。 MorphiaはAPIを介してこれをサポートしています。

有効な価格なしで本を挿入したくないとしましょう。 スキーマ検証を活用して、これを実現できます。

@Validation("{ price : { $gt : 0 } }")
public class Book {
    // ...
    @Property("price")
    private double cost;
    // ...
}

ここで使用できるMongoDBによって提供される豊富な検証セットがあります。

8. 代替のMongoDBODM

利用可能なMongoDBODMforJavaはMorphiaだけではありません。 私たちのアプリケーションで使用することを検討できる他のいくつかがあります。 ここではモルフィアとの比較について議論することはできませんが、私たちの選択肢を知ることは常に役に立ちます。

  • Spring Data :MongoDBを操作するためのSpringベースのプログラミングモデルを提供します
  • MongoJack :JSONからMongoDBオブジェクトへの直接マッピングを提供します

これは、Java用のMongoDB ODMの完全なリストではありませんが、いくつかの興味深い代替手段が利用可能です。

9. 結論

この記事では、MongoDBの基本的な詳細と、Javaなどのプログラミング言語からMongoDBに接続して操作するためのODMの使用について理解しました。 さらに、Java用のMongoDBODMとしてのMorphiaとそのさまざまな機能について説明しました。

いつものように、コードはGitHubのにあります。