最新の安定バージョンについては、Spring Data MongoDB 4.4.3 を使用してください! |
オブジェクトマッピング
豊富なマッピングのサポートは、MappingMongoConverter
によって提供されます。コンバーターは、ドメインオブジェクトを MongoDB ドキュメントにマップするための完全な機能セットを提供するメタデータモデルを保持します。マッピングメタデータモデルは、ドメインオブジェクトのアノテーションを使用して設定されます。ただし、インフラストラクチャは、メタデータ情報の唯一のソースとしてアノテーションを使用することに限定されません。MappingMongoConverter
では、一連の規則に従って、追加のメタデータを提供せずにオブジェクトをドキュメントにマップすることもできます。
このセクションでは、基礎、オブジェクトをドキュメントにマッピングするための規則の使用方法、およびアノテーションベースのマッピングメタデータでそれらの規則をオーバーライドする方法を含む、MappingMongoConverter
の機能について説明します。
オブジェクトマッピングの基礎
このセクションでは、Spring Data オブジェクトマッピング、オブジェクト作成、フィールドとプロパティへのアクセス、可変性と不変性の基礎について説明します。このセクションは、基になるデータストア(JPA など)のオブジェクトマッピングを使用しない Spring Data モジュールにのみ適用されることに注意してください。また、インデックス、列名やフィールド名のカスタマイズなど、ストア固有のオブジェクトマッピングについては、ストア固有のセクションを参照してください。
Spring Data オブジェクトマッピングの中心的なロールは、ドメインオブジェクトのインスタンスを作成し、ストアネイティブデータ構造をそれらにマッピングすることです。つまり、2 つの基本的な手順が必要です。
公開されたコンストラクターの 1 つを使用したインスタンスの作成。
すべての公開されたプロパティを具体化するインスタンスの設定。
オブジェクト作成
Spring Data は、その型のオブジェクトの具体化に使用される永続エンティティのコンストラクターを自動的に検出しようとします。解決アルゴリズムは次のように機能します。
@PersistenceCreator
でアノテーションが付けられた単一の静的ファクトリメソッドがある場合は、それが使用されます。コンストラクターが 1 つしかない場合は、それが使用されます。
複数のコンストラクターがあり、そのうちの 1 つだけに
@PersistenceCreator
アノテーションが付けられている場合は、それが使用されます。型が Java
Record
の場合、標準コンストラクターが使用されます。引数のないコンストラクターがある場合は、それが使用されます。他のコンストラクターは無視されます。
値の解決では、コンストラクター / ファクトリメソッドの引数名がエンティティのプロパティ名と一致することを前提としています。つまり、マッピングのすべてのカスタマイズ(異なるデータストア列またはフィールド名など)を含め、プロパティが入力されたかのように解決が実行されます。これには、クラスファイルで利用可能なパラメーター名情報、またはコンストラクターに存在する @ConstructorProperties
アノテーションも必要です。
値の解決は、ストア固有の SpEL 式を使用した Spring Framework の @Value
値アノテーションを使用してカスタマイズできます。詳細については、ストア固有のマッピングに関するセクションを参照してください。
プロパティ設定
エンティティのインスタンスが作成されると、Spring Data はそのクラスの残りのすべての永続プロパティを設定します。エンティティのコンストラクターによってすでに入力されていない場合(つまり、コンストラクターの引数リストを介して使用される場合)、ID プロパティが最初に入力され、循環オブジェクト参照の解決が可能になります。その後、コンストラクターによってまだ設定されていないすべての非一時的なプロパティがエンティティインスタンスに設定されます。そのために、次のアルゴリズムを使用します。
プロパティが不変であるが
with …
メソッドを公開している場合(以下を参照)、with …
メソッドを使用して、新しいプロパティ値を持つ新しいエンティティインスタンスを作成します。プロパティアクセス(つまり、getter および setter を介したアクセス)が定義されている場合、setter メソッドを呼び出しています。
プロパティが変更可能な場合、フィールドを直接設定します。
プロパティが不変の場合、永続化操作(オブジェクト作成を参照)で使用されるコンストラクターを使用して、インスタンスのコピーを作成します。
デフォルトでは、フィールド値を直接設定します。
次のエンティティを見てみましょう。
class Person {
private final @Id Long id; (1)
private final String firstname, lastname; (2)
private final LocalDate birthday;
private final int age; (3)
private String comment; (4)
private @AccessType(Type.PROPERTY) String remarks; (5)
static Person of(String firstname, String lastname, LocalDate birthday) { (6)
return new Person(null, firstname, lastname, birthday,
Period.between(birthday, LocalDate.now()).getYears());
}
Person(Long id, String firstname, String lastname, LocalDate birthday, int age) { (6)
this.id = id;
this.firstname = firstname;
this.lastname = lastname;
this.birthday = birthday;
this.age = age;
}
Person withId(Long id) { (1)
return new Person(id, this.firstname, this.lastname, this.birthday, this.age);
}
void setRemarks(String remarks) { (5)
this.remarks = remarks;
}
}
1 | identifier プロパティは final ですが、コンストラクターで null に設定されます。クラスは、識別子の設定に使用される withId(…) メソッドを公開します。インスタンスがデータストアに挿入され、識別子が生成されたとき。元の Person インスタンスは、新しいインスタンスが作成されるときに変更されません。通常、ストア管理される他のプロパティにも同じパターンが適用されますが、永続化操作のために変更する必要がある場合があります。永続化コンストラクター(6 を参照)は事実上コピーコンストラクターであり、プロパティの設定は新しい識別子値が適用された新しいインスタンスの作成に変換されるため、wither メソッドはオプションです。 |
2 | firstname および lastname プロパティは、getter を介して潜在的に公開される通常の不変のプロパティです。 |
3 | age プロパティは不変ですが、birthday プロパティから派生しています。示されている設計では、Spring Data は宣言された唯一のコンストラクターを使用するため、データベース値はデフォルト設定よりも優先されます。計算が優先されることを意図している場合でも、このコンストラクターがパラメーターとして age を受け取ることが重要です(無視される可能性があります)。そうしないと、プロパティ生成ステップは age フィールドを設定しようとし、不変で no with … メソッドが存在します。 |
4 | comment プロパティは変更可能で、そのフィールドを直接設定することによって入力されます。 |
5 | remarks プロパティは変更可能で、setter メソッドを呼び出すことによって設定されます。 |
6 | このクラスは、オブジェクト作成用のファクトリメソッドとコンストラクターを公開します。ここでの中心的な考え方は、@PersistenceCreator によるコンストラクターの曖昧性解消の必要性を回避するために、追加のコンストラクターの代わりにファクトリメソッドを使用することです。代わりに、プロパティのデフォルト設定はファクトリメソッド内で処理されます。Spring Data でオブジェクトのインスタンス化にファクトリメソッドを使用する場合は、@PersistenceCreator でアノテーションを付けます。 |
一般的な推奨事項
不変オブジェクトにこだわる — 不変オブジェクトは、オブジェクトを具体化するのはコンストラクターのみを呼び出すだけなので、簡単に作成できます。また、これにより、クライアントオブジェクトがオブジェクトの状態を操作できるようにする setter メソッドがドメインオブジェクトに散らばるのを防ぎます。それらが必要な場合は、同じ場所に配置された限られた型でのみ呼び出せるように、パッケージを保護することをお勧めします。コンストラクターのみの実体化は、プロパティの設定よりも最大 30% 高速です。
all-args コンストラクターを提供する — エンティティを不変の値としてモデル化できない、またはしたくない場合でも、オブジェクトのマッピングがプロパティの設定をスキップできるため、エンティティのすべてのプロパティを引数として取るコンストラクターを提供することには価値があります。最適なパフォーマンスのため。
@PersistenceCreator
を回避するために、オーバーロードされたコンストラクターの代わりにファクトリメソッドを使用します — 最適なパフォーマンスに必要なすべての引数コンストラクターでは、通常、自動生成識別子などを省略したアプリケーションユースケース固有のコンストラクターを公開します。これらの all-args コンストラクターのバリアントを公開する静的ファクトリメソッド。生成されたインスタンス生成クラスとプロパティアクセッサクラスを使用できるようにする制約を必ず守ってください。
生成される識別子については、すべての引数の永続化コンストラクター(推奨)または
with …
メソッドと組み合わせて final フィールドを使用しますLombok を使用してボイラープレートコードを回避します — 永続化操作は通常、すべての引数を取るコンストラクターを必要とするため、その宣言はフィールド割り当てに対するボイラープレートパラメーターの退屈な繰り返しとなりますが、Lombok の
@AllArgsConstructor
を使用することで回避することができます。
プロパティのオーバーライド
Java を使用すると、ドメインクラスを柔軟に設計できます。この場合、サブクラスは、スーパークラスで同じ名前ですでに宣言されているプロパティを定義できます。次の例を考えてみましょう。
public class SuperType {
private CharSequence field;
public SuperType(CharSequence field) {
this.field = field;
}
public CharSequence getField() {
return this.field;
}
public void setField(CharSequence field) {
this.field = field;
}
}
public class SubType extends SuperType {
private String field;
public SubType(String field) {
super(field);
this.field = field;
}
@Override
public String getField() {
return this.field;
}
public void setField(String field) {
this.field = field;
// optional
super.setField(field);
}
}
どちらのクラスも、割り当て可能な型を使用して field
を定義します。ただし、SubType
は SuperType.field
をシャドウします。クラスの設計によっては、コンストラクターを使用することが SuperType.field
を設定するための唯一のデフォルトのアプローチである可能性があります。または、setter で super.setField(…)
を呼び出すと、SuperType
で field
を設定できます。プロパティは同じ名前を共有しますが、2 つの異なる値を表す可能性があるため、これらすべてのメカニズムはある程度の競合を引き起こします。Spring Data は、型が割り当て可能でない場合、スーパー型のプロパティをスキップします。つまり、オーバーライドされたプロパティの型は、オーバーライドとして登録されるスーパー型のプロパティ型に割り当て可能である必要があります。そうでない場合、スーパー型のプロパティは一時的なものと見なされます。通常、個別のプロパティ名を使用することをお勧めします。
Spring Data モジュールは通常、異なる値を保持するオーバーライドされたプロパティをサポートします。プログラミングモデルの観点から、考慮すべきことがいくつかあります。
どのプロパティを永続化する必要がありますか(デフォルトでは、宣言されたすべてのプロパティになります)? これらに
@Transient
アノテーションを付けることで、プロパティを除外できます。データストアのプロパティを表す方法は? 異なる値に同じフィールド / 列名を使用すると、通常、データが破損するため、明示的なフィールド / 列名を使用してプロパティの少なくとも 1 つにアノテーションを付ける必要があります。
@AccessType(PROPERTY)
を使用することは、通常、setter 実装のさらなる仮定を行わずにスーパープロパティを設定することができないため、使用できません。
Kotlin サポート
Spring Data は、Kotlin の仕様を適合させて、オブジェクトの作成と変更を可能にします。
Kotlin オブジェクトの作成
Kotlin クラスはインスタンス化がサポートされています。すべてのクラスはデフォルトで不変であり、変更可能なプロパティを定義するには明示的なプロパティ宣言が必要です。
Spring Data は、その型のオブジェクトの具体化に使用される永続エンティティのコンストラクターを自動的に検出しようとします。解決アルゴリズムは次のように機能します。
@PersistenceCreator
でアノテーションが付けられたコンストラクターがある場合は、それが使用されます。型が Kotlin データクラスの場合、プライマリコンストラクターが使用されます。
@PersistenceCreator
でアノテーションが付けられた単一の静的ファクトリメソッドがある場合は、それが使用されます。コンストラクターが 1 つしかない場合は、それが使用されます。
複数のコンストラクターがあり、そのうちの 1 つだけに
@PersistenceCreator
アノテーションが付けられている場合は、それが使用されます。型が Java
Record
の場合、標準コンストラクターが使用されます。引数のないコンストラクターがある場合は、それが使用されます。他のコンストラクターは無視されます。
次の data
クラス Person
を検討してください。
data class Person(val id: String, val name: String)
上記のクラスは、明示的なコンストラクターを持つ典型的なクラスにコンパイルされます。別のコンストラクターを追加してこのクラスをカスタマイズし、@PersistenceCreator
でアノテーションを付けてコンストラクターの設定を示します。
data class Person(var id: String, val name: String) {
@PersistenceCreator
constructor(id: String) : this(id, "unknown")
}
Kotlin は、パラメーターが提供されない場合にデフォルト値を使用できるようにすることで、パラメーターのオプションをサポートしています。Spring Data がパラメーターのデフォルト設定を持つコンストラクターを検出した場合、データストアが値を提供しない(または単に null
を返す)場合、Kotlin はパラメーターのデフォルト設定を適用できるため、これらのパラメーターは存在しません。name
のパラメーターのデフォルト設定を適用する次のクラスを検討してください。
data class Person(var id: String, val name: String = "unknown")
name
パラメーターが結果の一部ではないか、その値が null
であるたびに、name
は unknown
にデフォルト設定されます。
委譲されたプロパティは Spring Data ではサポートされていません。マッピングメタデータは、Kotlin データクラスの委譲されたプロパティをフィルターします。その他の場合は、プロパティに @delegate:org.springframework.data.annotation.Transient のアノテーションを付けることで、委譲されたプロパティの合成フィールドを除外できます。 |
Kotlin データクラスのプロパティ設定
Kotlin では、すべてのクラスはデフォルトで不変であり、可変プロパティを定義するには明示的なプロパティ宣言が必要です。次の data
クラス Person
を検討してください。
data class Person(val id: String, val name: String)
このクラスは事実上不変です。Kotlin が既存のオブジェクトからすべてのプロパティ値をコピーしてメソッドに引数として提供されたプロパティ値を適用する新しいオブジェクトインスタンスを作成する copy(…)
メソッドを生成するときに、新しいインスタンスを作成できます。
Kotlin オーバーライドプロパティ
Kotlin では、プロパティのオーバーライド (英語) を宣言して、サブクラスのプロパティを変更できます。
open class SuperType(open var field: Int)
class SubType(override var field: Int = 1) :
SuperType(field) {
}
このような配置では、field
という名前の 2 つのプロパティがレンダリングされます。Kotlin は、各クラスの各プロパティのプロパティアクセサー(getter および setter)を生成します。事実上、コードは次のようになります。
public class SuperType {
private int field;
public SuperType(int field) {
this.field = field;
}
public int getField() {
return this.field;
}
public void setField(int field) {
this.field = field;
}
}
public final class SubType extends SuperType {
private int field;
public SubType(int field) {
super(field);
this.field = field;
}
public int getField() {
return this.field;
}
public void setField(int field) {
this.field = field;
}
}
SubType
の Getter および setter は、SubType.field
のみを設定し、SuperType.field
は設定しません。このような配置では、コンストラクターを使用することが SuperType.field
を設定するための唯一のデフォルトのアプローチです。SubType
にメソッドを追加して this.SuperType.field = …
を介して SuperType.field
を設定することは可能ですが、サポートされている規則の範囲外です。プロパティは同じ名前を共有しますが、2 つの異なる値を表す可能性があるため、プロパティのオーバーライドによってある程度の競合が発生します。通常、個別のプロパティ名を使用することをお勧めします。
Spring Data モジュールは通常、異なる値を保持するオーバーライドされたプロパティをサポートします。プログラミングモデルの観点から、考慮すべきことがいくつかあります。
どのプロパティを永続化する必要がありますか(デフォルトでは、宣言されたすべてのプロパティになります)? これらに
@Transient
アノテーションを付けることで、プロパティを除外できます。データストアのプロパティを表す方法は? 異なる値に同じフィールド / 列名を使用すると、通常、データが破損するため、明示的なフィールド / 列名を使用してプロパティの少なくとも 1 つにアノテーションを付ける必要があります。
@AccessType(PROPERTY)
を使用すると、スーパープロパティが設定できないため使用できません。
Kotlin 値クラス
Kotlin 値クラスは、基礎となる概念を明示するために、より表現力豊かなドメインモデル用に設計されています。Spring Data は、値クラスを使用してプロパティを定義する型の読み取りと書き込みができます。
次のドメインモデルを検討してください。
@JvmInline
value class EmailAddress(val theAddress: String) (1)
data class Contact(val id: String, val name:String, val emailAddress: EmailAddress) (2)
1 | Null 非許容値型を持つ単純な値クラス。 |
2 | EmailAddress 値クラスを使用してプロパティを定義するデータクラス。 |
非プリミティブ値型を使用する null 非許容プロパティは、コンパイルされたクラスで値型にフラット化されます。Null 許容プリミティブ値型または Null 許容値内値型は、ラッパー型で表現され、データベース内での値型の表現方法に影響します。 |
規約ベースのマッピング
MappingMongoConverter
には、追加のマッピングメタデータが提供されない場合にオブジェクトをドキュメントにマッピングするための規則がいくつかあります。規約は次のとおりです。
短い Java クラス名は、次の方法でコレクション名にマップされます。クラス
com.bigbank.SavingsAccount
はsavingsAccount
コレクション名にマップされます。すべてのネストされたオブジェクトは、DBRef としてではなく、ネストされたオブジェクトとしてドキュメントに保存されます。
コンバーターは、それに登録されている Spring コンバーターを使用して、オブジェクトプロパティのドキュメントフィールドおよび値へのデフォルトのマッピングをオーバーライドします。
オブジェクトのフィールドは、ドキュメント内のフィールドとの間の変換に使用されます。パブリック
JavaBean
プロパティは使用されません。引数ゼロ以外のコンストラクターが 1 つあり、そのコンストラクター引数名がドキュメントのトップレベルのフィールド名と一致する場合は、そのコンストラクターが使用されます。それ以外の場合は、引数ゼロのコンストラクターが使用されます。引数がゼロではないコンストラクターが複数ある場合、例外がスローされます。
_id
フィールドがマッピング層でどのように処理されるか。
MongoDB では、すべてのドキュメントに _id
フィールドが必要です。フィールドを指定しない場合は、ドライバーが生成された値で ObjectId を割り当てます。_id
フィールドは、一意であれば、配列以外の任意の型にすることができます。ドライバーは当然、すべてのプリミティブ型と MappingMongoConverter
を使用する Dates.When をサポートしますが、Java クラスのプロパティが _id
フィールドにマップされる方法を規定する特定のルールがあります。
以下に、どのフィールドが _id
ドキュメントフィールドにマップされるかを概説します。
@Id
(org.springframework.data.annotation.Id
) でアノテーションが付けられたフィールドは、_id
フィールドにマップされます。
さらに、ドキュメントフィールドの名前は@Field
アノテーションを使用してカスタマイズできます。この場合、ドキュメントにはフィールド_id
は含まれません。アノテーションのない
id
という名前のフィールドは、_id
フィールドにマップされます。
フィールドの定義 | MongoDB の結果の ID- フィールド名 |
---|---|
|
|
|
|
|
|
|
|
|
|
The following outlines what type conversion, if any, will be done on the property mapped to the _id document field.
-
If a field named
id
is declared as a String or BigInteger in the Java class it will be converted to and stored as an ObjectId if possible. ObjectId as a field type is also valid. If you specify a value forid
in your application, the conversion to an ObjectId is done by the MongoDB driver. If the specifiedid
value cannot be converted to an ObjectId, then the value will be stored as is in the document’s_id
field. This also applies if the field is annotated with@Id
. -
If a field is annotated with
@MongoId
in the Java class it will be converted to and stored as using its actual type. No further conversion happens unless@MongoId
declares a desired field type. If no value is provided for theid
field, a newObjectId
will be created and converted to the properties type. -
If a field is annotated with
@MongoId(FieldType.…)
in the Java class it will be attempted to convert the value to the declaredFieldType
. If no value is provided for theid
field, a newObjectId
will be created and converted to the declared type. -
If a field named
id
is not declared as a String, BigInteger, or ObjectID in the Java class then you should assign it a value in your application so it can be stored 'as-is' in the document’s_id
field. -
If no field named
id
is present in the Java class then an implicit_id
file will be generated by the driver but not mapped to a property or field of the Java class.
When querying and updating MongoTemplate
will use the converter to handle conversions of the Query
and Update
objects that correspond to the above rules for saving documents so field names and types used in your queries will be able to match what is in your domain classes.
Data Mapping and Type Conversion
Spring Data MongoDB supports all types that can be represented as BSON, MongoDB’s internal document format. In addition to these types, Spring Data MongoDB provides a set of built-in converters to map additional types. You can provide your own converters to adjust type conversion. See Custom Conversions - Overriding Default Mapping for further details.
Built in Type conversions:
Type | Type conversion | Sample |
---|---|---|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
|
native |
|
| ネイティブ |
|
| ネイティブ |
|
配列、 | ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
| ネイティブ |
|
|
converter |
|
|
converter |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
|
native |
|
|
converter |
|
|
converter / native (Java8)[1] |
|
|
converter / native (Java8)[2] |
|
|
converter |
|
|
converter |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
| コンバーター |
|
コレクションの処理 コレクションの処理は、MongoDB によって返される実際の値に応じて異なります。
通常、コンストラクターの作成を使用すると、設定する値を取得できます。プロパティ値がクエリレスポンスによって提供されない場合、プロパティの作成ではデフォルトの初期化値を使用できます。 |
マッピング設定
明示的に構成しない限り、MongoTemplate
を作成すると、デフォルトで MappingMongoConverter
のインスタンスが作成されます。MappingMongoConverter
の独自のインスタンスを作成できます。これにより、クラスパス内のドメインクラスが見つかる場所を指定できるようになり、Spring Data MongoDB がメタデータを抽出してインデックスを構築できるようになります。また、独自のインスタンスを作成することにより、Spring コンバーターを登録して、データベースとの間で特定のクラスをマップすることができます。
Java ベースまたは XML ベースのメタデータを使用して、MappingMongoConverter
、com.mongodb.client.MongoClient
、MongoTemplate を構成できます。次の例は構成を示しています。
Java
XML
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
@Override
public String getDatabaseName() {
return "database";
}
// the following are optional
@Override
public String getMappingBasePackage() { (1)
return "com.bigbank.domain";
}
@Override
void configureConverters(MongoConverterConfigurationAdapter adapter) { (2)
adapter.registerConverter(new org.springframework.data.mongodb.test.PersonReadConverter());
adapter.registerConverter(new org.springframework.data.mongodb.test.PersonWriteConverter());
}
@Bean
public LoggingEventListener<MongoMappingEvent> mappingEventsListener() {
return new LoggingEventListener<MongoMappingEvent>();
}
}
1 | マッピング基本パッケージは、MappingContext の事前初期化に使用されるエンティティのスキャンに使用されるルートパスを定義します。デフォルトでは、構成クラスパッケージが使用されます。 |
2 | 特定のドメイン型に対して追加のカスタムコンバーターを構成し、それらの型のデフォルトのマッピング手順をカスタム実装に置き換えます。 |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="
http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Default bean name is 'mongo' -->
<mongo:mongo-client host="localhost" port="27017"/>
<mongo:db-factory dbname="database" mongo-ref="mongoClient"/>
<!-- by default look for a Mongo object named 'mongo' - default name used for the converter is 'mappingConverter' -->
<mongo:mapping-converter base-package="com.bigbank.domain">
<mongo:custom-converters>
<mongo:converter ref="readConverter"/>
<mongo:converter>
<bean class="org.springframework.data.mongodb.test.PersonWriteConverter"/>
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
<bean id="readConverter" class="org.springframework.data.mongodb.test.PersonReadConverter"/>
<!-- set the mapping converter to be used by the MongoTemplate -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
</bean>
<bean class="org.springframework.data.mongodb.core.mapping.event.LoggingEventListener"/>
</beans>
AbstractMongoClientConfiguration
では、com.mongodb.client.MongoClient
を定義し、データベース名を指定するメソッドを実装する必要があります。AbstractMongoClientConfiguration
には、getMappingBasePackage(…)
という名前のメソッドもあり、これをオーバーライドして、@Document
アノテーションが付けられたクラスをスキャンする場所をコンバーターに指示できます。
customConversionsConfiguration
メソッドをオーバーライドすることで、コンバーターにコンバーターを追加できます。MongoDB のネイティブ JSR-310 サポートは、MongoConverterConfigurationAdapter.useNativeDriverJavaTimeCodecs()
を通じて有効にすることができます。前の例には、Spring の ApplicationContextEvent
インフラストラクチャにポストされる MongoMappingEvent
インスタンスをログに記録する LoggingEventListener
も示されています。
Java 時間の種類 MongoDB は |
AbstractMongoClientConfiguration は MongoTemplate インスタンスを作成し、それを mongoTemplate という名前でコンテナーに登録します。 |
base-package
プロパティは、@org.springframework.data.mongodb.core.mapping.Document
アノテーションが付けられたクラスをスキャンする場所を指定します。
Spring Boot に依存して Data MongoDB をブートストラップしたいが、構成の特定の側面をオーバーライドしたい場合は、その型の Bean を公開するとよいでしょう。カスタム変換の場合は、次のようにすることができます。Boot インフラストラクチャによって選択される、型 |
メタデータベースのマッピング
Spring Data MongoDB サポート内のオブジェクトマッピング機能を最大限に活用するには、マップされたオブジェクトに @Document
アノテーションを付ける必要があります。マッピングフレームワークにこのアノテーションを付ける必要はありませんが(アノテーションがなくても POJO は正しくマッピングされます)、クラスパススキャナーでドメインオブジェクトを見つけて前処理し、必要なメタデータを抽出できます。このアノテーションを使用しない場合、マッピングフレームワークは、ドメインオブジェクトのプロパティとそのメソッドを認識できるように内部メタデータモデルを構築する必要があるため、ドメインオブジェクトを最初に保存するときにアプリケーションのパフォーマンスがわずかに低下します。永続化します。次の例は、ドメインオブジェクトを示しています。
package com.mycompany.domain;
@Document
public class Person {
@Id
private ObjectId id;
@Indexed
private Integer ssn;
private String firstName;
@Indexed
private String lastName;
}
@Id アノテーションは、MongoDB _id プロパティにどのプロパティを使用するかをマッパーに伝え、@Indexed アノテーションは、ドキュメントのそのプロパティに対して createIndex(…) を呼び出すようにマッピングフレームワークに指示し、検索を高速化します。自動インデックス作成は、@Document アノテーションが付けられた型に対してのみ実行されます。 |
自動インデックス作成はデフォルトでは無効になっており、構成を通じて有効にする必要があります ( インデックスの作成を参照)。 |
マッピングアノテーションの概要
MappingMongoConverter はメタデータを使用して、オブジェクトのドキュメントへのマッピングを実行できます。次のアノテーションが利用可能です。
@Id
: ID 目的に使用されるフィールドをマークするためにフィールドレベルで適用されます。@MongoId
: ID 目的に使用されるフィールドをマークするためにフィールドレベルで適用されます。オプションのFieldType
を受け入れて ID 変換をカスタマイズします。@Document
: クラスレベルで適用され、このクラスがデータベースへのマッピングの候補であることを示します。データが保存されるコレクションの名前を指定できます。@DBRef
: com.mongodb.DBRef を使用して保存されることを示すためにフィールドに適用されます。@DocumentReference
: 別のドキュメントへのポインターとして保存されることを示すためにフィールドに適用されます。これは単一の値 (デフォルトでは ID ) にすることも、コンバーターを介して提供されるDocument
にすることもできます。@Indexed
: フィールドのインデックス付け方法を説明するためにフィールドレベルで適用されます。@CompoundIndex
(繰り返し可能な): 複合インデックスを宣言するために型レベルで適用されます。@GeoSpatialIndexed
: フィールドの地理インデックスを作成する方法を説明するためにフィールドレベルで適用されます。@TextIndexed
: テキストインデックスに含めるフィールドをマークするためにフィールドレベルで適用されます。@HashIndexed
: シャードクラスター全体でデータを分割するために、ハッシュインデックス内で使用するためにフィールドレベルで適用されます。@Language
: テキストインデックスの言語オーバーライドプロパティを設定するためにフィールドレベルで適用されます。@Transient
: デフォルトでは、すべてのフィールドがドキュメントにマップされます。このアノテーションは、それが適用されるフィールドをデータベースへの保存から除外します。コンバーターはコンストラクター引数の値を具体化できないため、一時プロパティは永続コンストラクター内で使用できません。@PersistenceConstructor
: データベースからオブジェクトをインスタンス化するときに使用する特定のコンストラクター (パッケージで protected コンストラクターも含む) をマークします。コンストラクターの引数は、取得されたドキュメント内のキー値に名前によってマップされます。@Value
: このアノテーションは Spring Framework の一部です。マッピングフレームワーク内では、コンストラクターの引数に適用できます。これにより、Spring 式言語ステートメントを使用して、データベースで取得したキーの値を、ドメインオブジェクトの構築に使用する前に変換できます。特定のドキュメントのプロパティを参照するには、次のような式を使用する必要があります。:@Value("#root.myProperty")
(root
は指定されたドキュメントのルートを指します)。@Field
: フィールドレベルで適用すると、MongoDB BSON ドキュメントで表現されるフィールドの名前と型を記述することができるため、名前と型をクラスのフィールド名やプロパティの型とは異なるものにすることができます。@Version
: フィールドレベルで適用されると、オプティミスティックロックに使用され、保存操作時に変更がチェックされます。初期値はzero
(プリミティブ型の場合はone
) で、更新のたびに自動的にバンプされます。
マッピングメタデータインフラストラクチャは、テクノロジに依存しない別の spring-data-commons プロジェクトで定義されます。MongoDB サポートでは、アノテーションベースのメタデータをサポートするために特定のサブクラスが使用されています。需要があれば、他の戦略を導入することも可能です。
より複雑なマッピングの例を次に示します。
@Document
@CompoundIndex(name = "age_idx", def = "{'lastName': 1, 'age': -1}")
public class Person<T extends Address> {
@Id
private String id;
@Indexed(unique = true)
private Integer ssn;
@Field("fName")
private String firstName;
@Indexed
private String lastName;
private Integer age;
@Transient
private Integer accountTotal;
@DBRef
private List<Account> accounts;
private T address;
public Person(Integer ssn) {
this.ssn = ssn;
}
@PersistenceConstructor
public Person(Integer ssn, String firstName, String lastName, Integer age, T address) {
this.ssn = ssn;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.address = address;
}
public String getId() {
return id;
}
// no setter for Id. (getter is only exposed for some unit testing)
public Integer getSsn() {
return ssn;
}
// other getters/setters omitted
}
独自のカスタムアノテーションを検討することもできます。
|
特殊なフィールド名
一般に、MongoDB は、ネストされたドキュメントまたは配列のパス区切り文字としてドット (.
) 文字を使用します。これは、クエリ (または更新ステートメント) で、a.b.c
のようなキーが以下に示すオブジェクト構造をターゲットにすることを意味します。
{
'a' : {
'b' : {
'c' : …
}
}
}
MongoDB 5.0 フィールド名まではドット (.
) を含めてはなりません。
MappingMongoConverter#setMapKeyDotReplacement
を使用すると、書き込み時のドットを別の文字に置き換えることで、Map
構造体を格納する際の制限の一部を回避できます。
converter.setMapKeyDotReplacement("-");
// ...
source.map = Map.of("key.with.dot", "value")
converter.write(source,...) // -> map : { 'key-with-dot', 'value' }
MongoDB 5.0 のリリースにより、特殊文字を含む Document
フィールド名に対するこの制限は解除されました。MongoDB リファレンス (英語) のフィールド名でのドットの使用に関する制限について詳しく読むことを強くお勧めします。
Map
構造でドットを許可するには、MappingMongoConverter
で preserveMapKeys
を設定してください。
@Field
を使用すると、2 つの方法でドットを考慮するようにフィールド名をカスタマイズできます。
@Field(name = "a.b")
: 名前はパスとみなされます。操作では、{ a : { b : … } }
などのネストされたオブジェクトの構造が想定されます。@Field(name = "a.b", fieldNameType = KEY)
: 名前はそのままの名前とみなされます。操作では、{ 'a.b' : … .. }
として指定された値を持つフィールドが必要です
MongoDB クエリと更新ステートメントの両方におけるドット文字の特殊な性質により、ドットを含むフィールド名は直接ターゲットにすることができないため、派生クエリメソッドでの使用から除外されます。次の
その生の表現は次のようになります
名前にドットが含まれるクエリフィールド
名前にドットが含まれるフィールドを更新します
上記は、特別なフィールドが最上位のドキュメントレベルに存在する簡単な例を示しています。ネストのレベルが増加すると、フィールドとの対話に必要な集計式の複雑さが増加します。 |
カスタマイズされたオブジェクト構築
マッピングサブシステムでは、コンストラクターに @PersistenceConstructor
アノテーションを付けることにより、オブジェクトの構成をカスタマイズできます。コンストラクターのパラメーターに使用される値は、次の方法で解決されます。
パラメーターに
@Value
アノテーションが付けられている場合、指定された式が評価され、その結果がパラメーター値として使用されます。Java 型に、入力ドキュメントの指定されたフィールドと名前が一致するプロパティがある場合、そのプロパティ情報を使用して、入力フィールド値を渡す適切なコンストラクターパラメーターが選択されます。これは、パラメーター名情報が java
.class
ファイルに存在する場合にのみ機能します。これを実現するには、デバッグ情報を使用してソースをコンパイルするか、Java 8 の javac 用の新しい-parameters
コマンドラインスイッチを使用します。それ以外の場合は、指定されたコンストラクターパラメーターをバインドできなかったことを示す
MappingException
がスローされます。
class OrderItem {
private @Id String id;
private int quantity;
private double unitPrice;
OrderItem(String id, @Value("#root.qty ?: 0") int quantity, double unitPrice) {
this.id = id;
this.quantity = quantity;
this.unitPrice = unitPrice;
}
// getters/setters ommitted
}
Document input = new Document("id", "4711");
input.put("unitPrice", 2.5);
input.put("qty",5);
OrderItem item = converter.read(OrderItem.class, input);
指定されたプロパティパスを解決できない場合、quantity パラメーターの @Value アノテーション内の SpEL 式は値 0 に戻ります。 |
@PersistenceConstructor
アノテーションを使用するための追加の例は、MappingMongoConverterUnitTests [GitHub] (英語) テストスイートにあります。
フレームワークイベントのマッピング
イベントは、マッピングプロセスのライフサイクル全体を通じて発生します。これについては、ライフサイクルイベントセクションで説明します。
Spring ApplicationContext でこれらの Bean を宣言すると、イベントが送出されるたびにそれらの Bean が呼び出されます。