1. 概要

このチュートリアルでは、Spring Data MongoDBのコア機能のいくつか(インデックス作成、一般的なアノテーション、コンバーター)について説明します。

2. インデックス

2.1. @Indexed

この注釈は、MongoDBでフィールドをインデックス付きとしてマークします。

@QueryEntity
@Document
public class User {
    @Indexed
    private String name;
    
    ... 
}

name フィールドにインデックスが付けられたので、MongoDBシェルのインデックスを見てみましょう。

db.user.getIndexes();

これが私たちが得るものです:

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    }
]

name フィールドの兆候がどこにもないことに驚かれるかもしれません!

これは、 Spring Data MongoDB 3.0以降、自動インデックス作成がデフォルトでオフになっているためです

ただし、 MongoConfigautoIndexCreation()メソッドを明示的にオーバーライドすることで、この動作を変更できます。

public class MongoConfig extends AbstractMongoClientConfiguration {

    // rest of the config goes here

    @Override
    protected boolean autoIndexCreation() {
        return true;
    }
}

MongoDBシェルのインデックスをもう一度確認してみましょう。

[
    {
        "v" : 1,
        "key" : {
             "_id" : 1
         },
        "name" : "_id_",
        "ns" : "test.user"
    },
    {
         "v" : 1,
         "key" : {
             "name" : 1
          },
          "name" : "name",
          "ns" : "test.user"
     }
]

ご覧のとおり、今回は2つのインデックスがあります。1つは _id です。これは、 @Id アノテーションが原因でデフォルトで作成され、2つ目はです。名前フィールド。

または、 Spring Bootを使用する場合は、spring.data.mongodb.auto-index-creationプロパティをtrueに設定できます。

2.2. プログラムでインデックスを作成する

プログラムでインデックスを作成することもできます。

mongoOps.indexOps(User.class).
  ensureIndex(new Index().on("name", Direction.ASC));

これで、フィールド name のインデックスが作成されました。結果は、前のセクションと同じになります。

2.3. 複合インデックス

MongoDBは、単一のインデックス構造が複数のフィールドへの参照を保持する複合インデックスをサポートします。

複合インデックスを使用した簡単な例を見てみましょう。

@QueryEntity
@Document
@CompoundIndexes({
    @CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
    //
}

emailフィールドとageフィールドを使用して複合インデックスを作成しました。 実際のインデックスを確認してみましょう。

{
    "v" : 1,
    "key" : {
        "email.id" : 1,
        "age" : 1
    },
    "name" : "email_age",
    "ns" : "test.user"
}

DBRefフィールドは@Indexでマークできないことに注意してください。このフィールドは、複合インデックスの一部としてのみ使用できます。

3. 一般的な注釈

3.1.  @Transient

予想どおり、この単純なアノテーションは、フィールドがデータベースに永続化されることを除外します。

public class User {
    
    @Transient
    private Integer yearOfBirth;
    // standard getter and setter

}

設定フィールドyearOfBirthを使用してユーザーを挿入しましょう。

User user = new User();
user.setName("Alex");
user.setYearOfBirth(1985);
mongoTemplate.insert(user);

ここで、データベースの状態を見ると、ファイルされたyearOfBirthが保存されていないことがわかります。

{
    "_id" : ObjectId("55d8b30f758fd3c9f374499b"),
    "name" : "Alex",
    "age" : null
}

したがって、クエリを実行して確認すると、次のようになります。

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getYearOfBirth()

結果はnullになります。

3.2. @Field

@Field は、JSONドキュメントのフィールドに使用されるキーを示します。

@Field("email")
private EmailAddress emailAddress;

これで、 emailAddress は、キー email:を使用してデータベースに保存されます。

User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("[email protected]");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);

そしてデータベースの状態:

{
    "_id" : ObjectId("55d076d80bad441ed114419d"),
    "name" : "Brendan",
    "age" : null,
    "email" : {
        "value" : "[email protected]"
    }
}

3.3. @PersistenceConstructorおよび@Value

@PersistenceConstructor は、パッケージで保護されているコンストラクターであっても、永続化ロジックで使用されるプライマリコンストラクターであることを示します。 コンストラクター引数は、名前によって、取得されたDBObjectのキー値にマップされます。

Userクラスのこのコンストラクターを見てみましょう。

@PersistenceConstructor
public User(String name, @Value("#root.age ?: 0") Integer age, EmailAddress emailAddress) {
    this.name =  name;
    this.age = age;
    this.emailAddress =  emailAddress;
}

ここでは、標準のSpring @Valueアノテーションが使用されていることに注意してください。 このアノテーションを使用すると、Spring式を使用して、ドメインオブジェクトの構築に使用する前に、データベースから取得したキーの値を変換できます。 これは、ここでは非常に強力で非常に便利な機能です。

この例では、 age が設定されていない場合、デフォルトで0に設定されます。

それがどのように機能するかを見てみましょう:

User user = new User();
user.setName("Alex");
mongoTemplate.insert(user);

私たちのデータベースは次のようになります。

{
    "_id" : ObjectId("55d074ca0bad45f744a71318"),
    "name" : "Alex",
    "age" : null
}

したがって、ageフィールドはnullですが、ドキュメントをクエリして age を取得すると、次のようになります。

mongoTemplate.findOne(Query.query(Criteria.where("name").is("Alex")), User.class).getAge();

結果は0になります。

4. コンバーター

ここで、Spring Data MongoDBのもう1つの非常に便利な機能であるコンバーター、特にMongoConverterを見てみましょう。

これは、これらのオブジェクトを格納および照会するときに、すべてのJavaタイプのDBObjectsへのマッピングを処理するために使用されます。

2つのオプションがあります–どちらかで作業できます MappingMongoConverter – また SimpleMongoConverter 以前のバージョンでは(これはSpring Data MongoDB M3で非推奨になり、その機能はに移動されました MappingMongoConverter )。

または、独自のカスタムコンバーターを作成することもできます。 そのためには、 Converter インターフェースを実装し、その実装をMongoConfig。に登録する必要があります。

簡単な例を見てみましょう。 ここでのJSON出力の一部で見たように、データベースに保存されたすべてのオブジェクトには、自動的に保存されるフィールド_classがあります。 ただし、永続化中にその特定のフィールドをスキップしたい場合は、MappingMongoConverterを使用してスキップできます。

まず、カスタムコンバータの実装は次のとおりです。

@Component
public class UserWriterConverter implements Converter<User, DBObject> {
    @Override
    public DBObject convert(User user) {
        DBObject dbObject = new BasicDBObject();
        dbObject.put("name", user.getName());
        dbObject.put("age", user.getAge());
        if (user.getEmailAddress() != null) {
            DBObject emailDbObject = new BasicDBObject();
            emailDbObject.put("value", user.getEmailAddress().getValue());
            dbObject.put("email", emailDbObject);
        }
        dbObject.removeField("_class");
        return dbObject;
    }
}

ここで直接フィールドを削除することで、_classを永続化しないという目標を簡単に達成できることに注目してください。

次に、カスタムコンバータを登録する必要があります。

private List<Converter<?,?>> converters = new ArrayList<Converter<?,?>>();

@Override
public MongoCustomConversions customConversions() {
    converters.add(new UserWriterConverter());
    return new MongoCustomConversions(converters);
}

もちろん、次のことが必要な場合は、XML構成でも同じ結果を得ることができます。

<bean id="mongoTemplate" 
  class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongo" ref="mongo"/>
    <constructor-arg ref="mongoConverter" />
    <constructor-arg name="databaseName" value="test"/>
</bean>

<mongo:mapping-converter id="mongoConverter" base-package="org.baeldung.converter">
    <mongo:custom-converters base-package="com.baeldung.converter" />
</mongo:mapping-converter>

ここで、新しいユーザーを保存すると、次のようになります。

User user = new User();
user.setName("Chris");
mongoOps.insert(user);

データベース内の結果のドキュメントには、クラス情報が含まれなくなります。

{
    "_id" : ObjectId("55cf09790bad4394db84b853"),
    "name" : "Chris",
    "age" : null
}

5. 結論

このチュートリアルでは、Spring Data MongoDBの操作に関するいくつかのコア概念(インデックス作成、一般的なアノテーション、コンバーター)について説明しました。

これらすべての例とコードスニペットの実装は、GitHubにあります。