sql >> データベース >  >> NoSQL >> MongoDB

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

    1。概要

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

    2。インデックス

    2.1。 @Indexed

    このアノテーションは、フィールドをインデックス付きとしてマークします MongoDBの場合:

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

    これで名前 フィールドにはインデックスが付けられています–MongoDBシェルのインデックスを見てみましょう:

    db.user.getIndexes();

    取得できるものは次のとおりです。

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

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

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

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

    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を使用して複合インデックスを作成しました および年齢 田畑。実際のインデックスを確認してみましょう:

    {
        "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のキー値にマップされます。 。

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

    @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式を使用して、ドメインオブジェクトの構築に使用する前に、データベースから取得したキーの値を変換できます。これは非常に強力で非常に便利な機能です。

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

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

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

    データベースは次のようになります:

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

    つまり、年齢 フィールドはnull 、ただし、ドキュメントをクエリして年齢を取得する場合 :

    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に移動されました。 )

    または、独自のカスタムコンバーターを作成することもできます。そのためには、コンバーターを実装する必要があります。 インターフェイスを作成し、実装を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
    }

    1. MongoDB $ toString

    2. Node.jsでRESTfulAPIを最適に作成する方法

    3. 接続できないherokuにredisをデプロイする

    4. MongoDBでインデックスサイズを推定するためのツールはありますか?