1. 개요

이 튜토리얼에서는 인덱싱, 공통 어노테이션 및 변환기와 같은 SpringData MongoDB의 핵심 기능 중 일부를 살펴볼 것입니다.

2. 인덱스

2.1. @ 색인

이 어노테이션은 필드를 MongoDB에서 인덱싱 된 것으로 표시합니다 .

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

이제 이름 필드가 색인화되었으므로 MongoDB 셸의 색인을 살펴 보겠습니다.

db.user.getIndexes();

우리가 얻는 것은 다음과 같습니다.

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

우리는 어디에도 이름 필드의 흔적이 없다는 것에 놀랐을 것입니다 !

이는 SpringData 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"
     }
]

보시다시피 이번에는 두 개의 인덱스가 있습니다. 하나는 _id 입니다.이 인덱스 중 하나 @Id 어노테이션 으로 인해 기본적으로 생성되었으며 두 번째는 이름 필드입니다.

또는 Spring Boot를 사용하는 경우 spring.data.mongodb.auto-index-creation 속성을 true로 설정할 수 있습니다 .

2.2. 프로그래밍 방식으로 인덱스 만들기

프로그래밍 방식으로 색인을 만들 수도 있습니다.

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

이제 필드 이름에 대한 인덱스를 만들었 으며 결과는 이전 섹션과 동일합니다.

2.3. 복합 인덱스

MongoDB는 단일 인덱스 구조가 여러 필드에 대한 참조를 보유하는 복합 인덱스를 지원합니다.

복합 인덱스를 사용하는 간단한 예를 살펴 보겠습니다.

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

이메일연령 필드 로 복합 색인을 만들었습니다 . 이제 실제 색인을 확인해 보겠습니다.

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

• 그래도 참고 DBRef의 필드로 표시 할 수 없습니다 @index는 -이 필드는 복합 인덱스의 일부가 될 수 있습니다.

3. 공통 어노테이션

3.1. @과도 현상

예상대로이 간단한 어노테이션은 필드가 데이터베이스에서 유지되지 않도록 제외합니다.

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 는 JSON 문서의 필드에 사용할 키를 나타냅니다.

@Field("email")
private EmailAddress emailAddress;

이제 emailAddress 는 키 이메일을 사용하여 데이터베이스에 저장됩니다 .

User user = new User();
user.setName("Brendan");
EmailAddress emailAddress = new EmailAddress();
emailAddress.setValue("a@gmail.com");
user.setEmailAddress(emailAddress);
mongoTemplate.insert(user);

그리고 데이터베이스의 상태 :

{
    "_id" : ObjectId("55d076d80bad441ed114419d"),
    "name" : "Brendan",
    "age" : null,
    "email" : {
        "value" : "a@gmail.com"
    }
}

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 Expressions를 사용하여 데이터베이스에서 검색된 키 값을 도메인 개체를 구성하는 데 사용되기 전에 변환 할 수 있습니다. 이것은 매우 강력하고 매우 유용한 기능입니다.

이 예에서 연령 이 설정되지 않은 경우 기본적 으로 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. 변환기

이제 SpringData MongoDB의 또 다른 매우 유용한 기능인 변환기, 특히 MongoConverter 에 대해 살펴 보겠습니다 .

이는 이러한 객체를 저장하고 쿼리 할 때 모든 Java 유형을 DBObject에 매핑하는 데 사용됩니다 .

두 가지 옵션이 있습니다. MappingMongoConverter로 작업 할 수 있습니다. 또는 이전 버전의 SimpleMongoConverter ( SpringData 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. 결론

이 튜토리얼에서 우리는 SpringData MongoDB 작업의 핵심 개념 인 인덱싱, 공통 어노테이션 및 변환기를 다루었습니다.

이러한 모든 예제 및 코드 스 니펫의 구현은 GitHub 에서 찾을 수 있습니다  .