그날그날메모

Morphia 소개 – MongoDB 용 Java ODM

Java

Morphia 소개 – MongoDB 용 Java ODM

그날그날메모 2021. 4. 21. 19:24

1. 개요

이 예제에서는 Java에서 MongoDB 용 ODM (Object Document Mapper) 인 Morphia 를 사용하는 방법을 이해합니다 .

이 과정에서 ODM이 무엇인지, 그리고 그것이 어떻게 MongoDB와의 작업을 용이하게하는지 이해하게 될 것입니다.

2. ODM 이란 무엇입니까 ?

이 분야에 입문하지 않은 사람들을 위해 MongoDB 는 본질적으로 배포되도록 구축 된 문서 지향 데이터베이스입니다 . 간단히 말해서 문서 지향 데이터베이스는 반 구조화 된 데이터를 구성하는 스키마없는 방법에 불과한 문서를 관리 합니다 . 그들은 기존의 SQL 데이터베이스 조직에서 명백하게 벗어난 이름을 따서 명명 된 더 광범위하고 느슨하게 정의 된 NoSQL 데이터베이스의 우산에 속합니다.

MongoDB는 Java와 같이 널리 사용되는 거의 모든 프로그래밍 언어 용 드라이버를 제공합니다 . 이 드라이버는 MongoDB 작업을위한 추상화 계층을 제공하므로 Wire Protocol을 직접 사용하지 않습니다. 이를 관계형 데이터베이스에 대한 JDBC 드라이버 구현을 제공하는 Oracle이라고 생각하십시오.

그러나 JDBC로 직접 작업했던 시절을 떠올려 보면 특히 객체 지향 패러다임에서 JDBC가 얼마나 지저분해질 수 있는지 알 수 있습니다. 다행히도 Hibernate와 같은 ORM (Object Relational Mapping) 프레임 워크가 있습니다. MongoDB와 크게 다르지 않습니다.

저수준 드라이버로 확실히 작업 할 수 있지만 작업을 수행하려면 훨씬 더 많은 상용구가 필요합니다. 여기에는 ODM (Object Document Mapper)이라는 ORM과 유사한 개념이 있습니다. Morphia는 Java 프로그래밍 언어를위한 공간을 정확히 채우고 MongoDB 용 Java 드라이버 위에서 작동합니다.

3. 의존성 설정

우리는 코드를 작성하기에 충분한 이론을 보았습니다. 예제에서는 도서 라이브러리를 모델링하고 Morphia를 사용하여 MongoDB에서 관리하는 방법을 살펴 보겠습니다.

그러나 시작하기 전에 몇 가지 의존성을 설정해야합니다.

3.1. MongoDB

작업하려면 MongoDB의 실행중인 인스턴스가 있어야합니다. 이를 얻는 방법에는 여러 가지가 있으며 가장 간단한 방법은 로컬 머신에 커뮤니티 에디션다운로드하여 설치 하는 것입니다.

MongoDB가 실행되는 포트를 포함하여 모든 기본 구성을 그대로 두어야합니다.

3.2. 모르 피아

Maven Central 에서 사전 빌드 된 Morphia 용 JAR을 다운로드하여 Java 프로젝트에서 사용할 수 있습니다.

그러나 가장 간단한 방법은 Maven과 같은 의존성 관리 도구를 사용하는 것입니다.

<dependency>
    <groupId>dev.morphia.morphia</groupId>
    <artifactId>core</artifactId>
    <version>1.5.3</version>
</dependency>

4. Morphia를 사용하여 연결하는 방법?

이제 MongoDB를 설치 및 실행하고 Java 프로젝트에서 Morphia를 설정 했으므로 Morphia를 사용하여 MongoDB에 연결할 준비가되었습니다.

이를 달성하는 방법을 살펴 보겠습니다.

Morphia morphia = new Morphia();
morphia.mapPackage("com.baeldung.morphia");
Datastore datastore = morphia.createDatastore(new MongoClient(), "library");
datastore.ensureIndexes();

그게 다야! 이것을 더 잘 이해합시다. 매핑 작업이 작동하려면 두 가지가 필요합니다.

  1. 매퍼 : Java POJO를 MongoDB 컬렉션매핑 하는 역할을 합니다 . 위의 코드 스 니펫에서 Morphia 는이를 담당하는 클래스입니다. POJO를 찾아야하는 패키지를 구성하는 방법에 유의하십시오.
  2. 연결 : 매퍼가 다른 작업을 실행할 수있는 MongoDB 데이터베이스에 대한 연결입니다. Datastore 클래스 MongoClient 의 인스턴스 (Java MongoDB 드라이버에서)와 MongoDB 데이터베이스의 이름을 매개 변수 로 사용하여 .

따라서 우리는 모두이 Datastore 를 사용 하고 항목으로 작업 할 준비가되었습니다.

5. 엔티티와 작업하는 방법?

새로 생성 된 Datastore를 사용하려면 먼저 사용할 도메인 항목을 정의해야합니다.

5.1. 단순 엔티티

몇 가지 속성이 있는 간단한 Book 엔티티를 정의하는 것으로 시작하겠습니다 .

@Entity("Books")
public class Book {
    @Id
    private String isbn;
    private String title;
    private String author;
    @Property("price")
    private double cost;
    // constructors, getters, setters and hashCode, equals, toString implementations
}

여기서 주목할 몇 가지 흥미로운 사항이 있습니다.

  • Morphia의 ODM 매핑대해이 POJO를 한정하는 @ Entity 어노테이션을 확인하십시오.
  • 기본적으로 Morphia는 클래스 이름으로 MongoDB의 컬렉션에 엔티티를 매핑하지만 명시 적으로 재정의 할 수 있습니다 (  여기 에서 엔티티 Book에 대해 수행 한 것처럼 ).
  • 기본적으로 Morphia는 변수 이름으로 엔티티의 변수를 MongoDB 컬렉션의 키에 매핑하지만 다시이 값을 재정의 할 수 있습니다 (  여기서 가변 비용에 대해 수행 한 것처럼 )
  • 마지막으로, @ Id 어노테이션에 의해 기본 키 역할을하는 엔터티의 변수표시 해야합니다 (여기에서 책에 ISBN을 사용하는 것처럼).

5.2. 관계가있는 엔티티

그러나 현실 세계에서 엔티티는보기만큼 단순하지 않으며 서로 복잡한 관계를 가지고 있습니다. 예를 들어, 우리의 단순한 엔터티 발행인을 가질 수 있고 다른 동반 책을 참조 할 수 있습니다. 어떻게 모델링합니까?

MongoDB는 관계를 구축하는 두 가지 메커니즘 인 참조 및 포함을 제공 합니다. 이름에서 알 수 있듯이 참조를 통해 MongoDB는 관련 데이터를 동일하거나 다른 컬렉션에 별도의 문서로 저장하고 ID를 사용하여 참조합니다.

반대로 임베딩을 사용하면 MongoDB는 상위 문서 자체에 관계를 저장하거나 임베드합니다.

어떻게 사용할 수 있는지 봅시다. 책에 Publisher삽입하는 것으로 시작하겠습니다 .

@Embedded
private Publisher publisher;

충분히 간단합니다. 이제 다른 책에 대한 참조를 추가해 보겠습니다.

@Reference
private List<Book> companionBooks;

그게 다입니다. Morphia는 MongoDB에서 지원하는 모델 관계에 편리한 어노테이션을 제공합니다. 그러나 참조와 임베딩 의 선택은 데이터 모델 복잡성, 중복성 및 다른 고려 사항 간의 일관성에서 비롯되어야합니다 .

이 연습은 관계형 데이터베이스의 정규화와 유사합니다.

이제 Datastore를 사용하여 Book에서 몇 가지 작업을 수행 할 준비가되었습니다 .

6. 몇 가지 기본 작업

Morphia를 사용하여 몇 가지 기본 작업을 수행하는 방법을 살펴 보겠습니다.

6.1. 저장

MongoDB 데이터베이스 라이브러리Book 의 인스턴스를 만드는 가장 간단한 작업부터 시작하겠습니다 .

Publisher publisher = new Publisher(new ObjectId(), "Awsome Publisher");

Book book = new Book("9781565927186", "Learning Java", "Tom Kirkman", 3.95, publisher);
Book companionBook = new Book("9789332575103", "Java Performance Companion", 
  "Tom Kirkman", 1.95, publisher);

book.addCompanionBooks(companionBook);

datastore.save(companionBook);
datastore.save(book);

이것은 Morphia가 MongoDB 데이터베이스에 컬렉션을 생성하고 (존재하지 않는 경우) upsert 작업을 수행하도록하기에 충분합니다.

6.2. 질문

MongoDB에서 방금 만든 책을 쿼리 할 수 ​​있는지 살펴 보겠습니다.

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(1, books.size());

assertEquals(book, books.get(0));

Morphia에서 문서를 쿼리하는 것은 Datastore를 사용하여 쿼리를 생성 한 다음 선언적으로 필터를 추가하는 것으로 시작하여 함수형 프로그래밍을 좋아하는 사람들을 기쁘게합니다!

Morphia는 필터와 연산자를 사용하여 훨씬 더 복잡한 쿼리 구성을 지원합니다 . 또한 Morphia는 쿼리에서 결과의 제한, 건너 뛰기 및 순서 지정을 허용합니다.

또한 Morphia를 사용하면 필요한 경우 더 많은 제어를 위해 MongoDB 용 Java 드라이버로 작성된 원시 쿼리를 사용할 수 있습니다.

6.3. 최신 정보

저장 작업은 기본 키가 일치하는 경우 업데이트를 처리 할 수 ​​있지만 Morphia는 문서를 선택적으로 업데이트하는 방법을 제공합니다.

Query<Book> query = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java");

UpdateOperations<Book> updates = datastore.createUpdateOperations(Book.class)
  .inc("price", 1);

datastore.update(query, updates);

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(4.95, books.get(0).getCost());

여기에서는 쿼리가 반환 한 모든 책의 가격을 1 씩 올리는 쿼리 및 업데이트 작업을 작성합니다.

6.4. 지우다

마지막으로 생성 된 것은 삭제해야합니다! 다시 말하지만 Morphia를 사용하면 매우 직관적입니다.

Query<Book> query = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java");

datastore.delete(query);

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .find()
  .toList();

assertEquals(0, books.size());

이전과 매우 유사하게 쿼리를 만들고 Datastore 에서 삭제 작업을 실행합니다 .

7. 고급 사용법

MongoDB에는 집계, 인덱싱 및 기타 여러 가지 고급 작업이 있습니다 . Morphia를 사용하여 모든 작업을 수행하는 것은 불가능하지만 일부를 달성하는 것은 확실히 가능합니다. 다른 사람들에게는 슬프게도 MongoDB 용 Java 드라이버로 돌아 가야합니다.

Morphia를 통해 수행 할 수있는 이러한 고급 작업 중 일부에 집중하겠습니다.

7.1. 집합

MongoDB의 집계를 사용 하면 일련의 문서에서 작동하고 집계 된 출력을 생성 할 수있는 파이프 라인에서 일련의 작업 을 정의 할 수 있습니다 .

Morphia에는 이러한 집계 파이프 라인을 지원하는 API가 있습니다.

저자별로 모든 책을 그룹화하는 방식으로 도서관 데이터를 집계한다고 가정 해 보겠습니다.

Iterator<Author> iterator = datastore.createAggregation(Book.class)
  .group("author", grouping("books", push("title")))
  .out(Author.class);

그렇다면 어떻게 작동합니까? 동일한 이전 Datastore를 사용하여 집계 파이프 라인을 만드는 것으로 시작합니다 . 예를 들어 Book here 와 같이 집계 작업을 수행하려는 엔티티를 제공해야합니다 .

다음으로 "저자"별로 문서를 그룹화하고 "책"이라는 키 아래에 "제목"을 집계하려고합니다. 마지막으로, 우리는 여기서 ODM으로 작업하고 있습니다. 따라서 집계 된 데이터를 수집 할 엔티티를 정의해야합니다. 여기서는 Author 입니다.

물론 책이라는 변수 를 사용하여 Author 라는 엔티티를 정의해야합니다 .

@Entity
public class Author {
    @Id
    private String name;
    private List<String> books;
    // other necessary getters and setters
}

물론 이것은 MongoDB에서 제공하는 매우 강력한 구조의 표면을 긁어 모은 것이며 자세한 내용은 자세히 살펴볼 수 있습니다 .

7.2. 투사

MongoDB의 프로젝션을 사용하면 쿼리의 문서에서 가져 오려는 필드 만 선택할 수 있습니다. 문서 구조가 복잡하고 무거운 경우 필드가 몇 개만 필요할 때 정말 유용 할 수 있습니다.

쿼리에서 제목이있는 책만 가져 오면된다고 가정 해 보겠습니다.

List<Book> books = datastore.createQuery(Book.class)
  .field("title")
  .contains("Learning Java")
  .project("title", true)
  .find()
  .toList();
 
assertEquals("Learning Java", books.get(0).getTitle());
assertNull(books.get(0).getAuthor());

여기서 볼 수 있듯이 저자 및 기타 필드가 아닌 결과의 제목 만 반환됩니다. 그러나 MongoDB에 다시 저장할 때 예상 출력을 사용할 때는주의해야합니다. 이로 인해 데이터가 손실 될 수 있습니다!

7.3. 인덱싱

인덱스는 데이터베이스의 쿼리 최적화에서 매우 중요한 역할을합니다 (관계형 및 많은 비 관계형).

MongoDB 는 기본적으로 기본 키에 생성 된 고유 인덱스를 사용하여 컬렉션 수준에서 인덱스를 정의합니다 . 또한 MongoDB를 사용하면 문서 내의 모든 필드 또는 하위 필드에 인덱스를 만들 수 있습니다. 생성하려는 쿼리에 따라 키에 인덱스를 생성하도록 선택해야합니다.

예를 들어, 우리의 예에서 우리는 종종 쿼리를 끝내기 때문에 Book의 "title"필드에 인덱스를 만들 수 있습니다 .

@Indexes({
  @Index(
    fields = @Field("title"),
    options = @IndexOptions(name = "book_title")
  )
})
public class Book {
    // ...
    @Property
    private String title;
    // ...
}

물론 생성되는 인덱스의 뉘앙스를 조정하기 위해 추가 인덱싱 옵션을 전달할 수 있습니다. 필드는 인덱스에서 사용하기 위해 @ Property어노테이션을 달아야합니다 .

또한 클래스 수준 인덱스와 별도로 Morphia에는 필드 수준 인덱스를 정의하는 어노테이션도 있습니다.

7.4. 스키마 유효성 검사

업데이트 또는 삽입 작업을 수행하는 동안 MongoDB가 사용할 수있는 컬렉션에 대한 데이터 유효성 검사 규칙 을 제공하는 옵션이 있습니다 . Morphia는 API를 통해이를 지원합니다.

유효한 가격이없는 책을 삽입하고 싶지 않다고 가정 해 보겠습니다. 이를 위해 스키마 유효성 검사를 활용할 수 있습니다.

@Validation("{ price : { $gt : 0 } }")
public class Book {
    // ...
    @Property("price")
    private double cost;
    // ...
}

여기에 사용할 수있는 MongoDB 에서 제공하는 다양한 유효성 검사가 있습니다.

8. 대체 MongoDB ODM

Morphia는 Java 용으로 사용 가능한 유일한 MongoDB ODM이 아닙니다. 우리의 응용 프로그램에서 사용할 수있는 몇 가지 다른 것이 있습니다. 여기서 Morphia와의 비교에 대한 논의는 가능하지 않지만 항상 우리의 옵션을 아는 것이 유용합니다.

  • SpringData : MongoDB 작업을위한 Spring 기반 프로그래밍 모델 제공
  • MongoJack : JSON에서 MongoDB 객체로의 직접 매핑 제공

이것은 Java 용 MongoDB ODM의 전체 List은 아니지만 몇 가지 흥미로운 대안이 있습니다!

9. 결론

이 기사에서 우리는 MongoDB의 기본 세부 사항과 Java와 같은 프로그래밍 언어에서 MongoDB를 연결하고 작동하기 위해 ODM을 사용하는 방법을 이해했습니다. 우리는 Morphia를 Java 용 MongoDB ODM 및 다양한 기능으로 더 탐구했습니다.

항상 그렇듯이 코드는 GitHub 에서 찾을 수 있습니다 .

참고
  • https://docs.spring.io/spring-framework/docs/current/reference/html
  • https://www.baeldung.com/mongodb-morphia