Spring Data MongoDB - インデックス、アノテーション、コンバーター

Spring Data MongoDB –インデックス、注釈、コンバーター

1. 概要

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

2. 索引

2.1. @Indexed

MongoDBのこのアノテーションmarks the field as indexed

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

    ...
}

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

db.user.getIndexes();

データベースレベルでの情報は次のとおりです。

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

ご覧のとおり、2つのインデックスがあります。そのうちの1つは_idです。これは、@Idアノテーションとthe second one is our name field.のためにデフォルトで作成されました。

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.に登録する必要があります。

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

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

@Component
public class UserWriterConverter implements Converter {
    @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> converters = new ArrayList>();

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

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


    
    
    



    

次に、新しいユーザーを保存するとき:

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

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

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

5. 結論

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

これらすべての例とコードスニペットcan be found inmy github projectの実装–これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。