MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Wprowadzenie do Morphii – Java ODM dla MongoDB

1. Przegląd

W tym samouczku zrozumiemy, jak używać Morphii, Object Document Mapper (ODM) dla MongoDB w Javie.

W trakcie tego procesu zrozumiemy również, czym jest ODM i jak ułatwia pracę z MongoDB.

2. Co to jest ODM ?

Dla niewtajemniczonych w tym obszarze MongoDB to zorientowana na dokumenty baza danych, stworzona do dystrybucji z natury . Bazy danych zorientowane na dokumenty, w prostych słowach, zarządzają dokumentami, które są niczym innym jak bezschematycznym sposobem organizowania danych częściowo ustrukturyzowanych . Obejmują one szerszy i luźniej zdefiniowany parasol baz danych NoSQL, nazwany tak od ich widocznego odejścia od tradycyjnej organizacji baz danych SQL.

MongoDB zapewnia sterowniki dla prawie wszystkich popularnych języków programowania, takich jak Java . Te sterowniki oferują warstwę abstrakcji do pracy z MongoDB, więc nie pracujemy bezpośrednio z Wire Protocol. Pomyśl o tym jako o Oracle zapewniającym implementację sterownika JDBC dla ich relacyjnej bazy danych.

Jeśli jednak przypomnimy sobie nasze dni pracy bezpośrednio z JDBC, możemy docenić, jak może być bałagan — zwłaszcza w paradygmacie zorientowanym obiektowo. Na szczęście mamy na ratunek frameworki Object Relational Mapping (ORM), takie jak Hibernate. Nie różni się zbytnio w przypadku MongoDB.

Chociaż z pewnością możemy pracować z niskopoziomowym sterownikiem, do wykonania tego zadania potrzeba znacznie więcej schematu. Tutaj mamy podobną koncepcję do ORM o nazwie Object Document Mapper (ODM) . Morphia dokładnie wypełnia tę przestrzeń dla języka programowania Java i działa na sterowniku Java dla MongoDB.

3. Konfigurowanie zależności

Widzieliśmy wystarczająco dużo teorii, aby wprowadzić nas w jakiś kod. Dla naszych przykładów stworzymy model biblioteki książek i zobaczymy, jak możemy nią zarządzać w MongoDB za pomocą Morphia.

Ale zanim zaczniemy, musimy skonfigurować niektóre zależności.

3.1. MongoDB

Do pracy musimy mieć uruchomioną instancję MongoDB. Istnieje kilka sposobów, aby to uzyskać, a najprostszym jest pobranie i zainstalowanie wersji Community Edition na naszym lokalnym komputerze.

Powinniśmy pozostawić wszystkie domyślne konfiguracje bez zmian, w tym port, na którym działa MongoDB.

3.2. Morfia

Możemy pobrać gotowe pliki JAR dla Morphii z Maven Central i użyć ich w naszym projekcie Java.

Jednak najprostszym sposobem jest użycie narzędzia do zarządzania zależnościami, takiego jak Maven:

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

4. Jak połączyć się za pomocą Morphii?

Teraz, gdy mamy zainstalowaną i uruchomioną MongoDB oraz skonfigurowaną Morphię w naszym projekcie Java, jesteśmy gotowi do połączenia się z MongoDB za pomocą Morphii.

Zobaczmy, jak możemy to osiągnąć:

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

To prawie tyle! Zrozummy to lepiej. Aby nasze operacje mapowania działały, potrzebujemy dwóch rzeczy:

  1. Mapper:jest odpowiedzialny za mapowanie naszych Java POJO do kolekcji MongoDB . W powyższym fragmencie kodu Morphia jest za to odpowiedzialna klasa. Zwróć uwagę, jak konfigurujemy pakiet, w którym powinien szukać naszych POJO.
  2. Połączenie:Jest to połączenie z bazą danych MongoDB, na której program mapujący może wykonywać różne operacje. Klasa Datastore przyjmuje jako parametr instancję MongoClient (ze sterownika Java MongoDB) i nazwę bazy danych MongoDB, zwracając aktywne połączenie do pracy .

Tak więc wszyscy jesteśmy gotowi do korzystania z tego Datastore i współpracować z naszymi podmiotami.

5. Jak pracować z podmiotami?

Zanim będziemy mogli korzystać z naszego świeżo upieczonego Datastore , musimy zdefiniować niektóre encje domeny, z którymi będziemy pracować.

5.1. Prosta jednostka

Zacznijmy od zdefiniowania prostej książki jednostka z pewnymi atrybutami:

@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
}

Należy tutaj zwrócić uwagę na kilka interesujących rzeczy:

  • Zwróć uwagę na adnotację @Entity kwalifikuje to POJO do mapowania ODM przez Morphię
  • Morphia domyślnie mapuje encję do kolekcji w MongoDB według nazwy jej klasy, ale możemy to wyraźnie zmienić (tak jak zrobiliśmy to dla encji Książka tutaj)
  • Morphia domyślnie mapuje zmienne w encji na klucze w kolekcji MongoDB według nazwy zmiennej, ale znowu możemy to zmienić (tak jak zrobiliśmy to dla zmiennej koszt tutaj)
  • Na koniec musimy oznaczyć zmienną w encji, aby działała jako klucz podstawowy za pomocą adnotacji @Id (tak jak używamy ISBN dla naszej książki tutaj)

5.2. Podmioty mające relacje

Jednak w prawdziwym świecie byty nie są tak proste, jak wyglądają i mają ze sobą złożone relacje. Na przykład nasza prosta encja Book może mieć Wydawcę i może odwoływać się do innych książek towarzyszących. Jak je modelujemy?

MongoDB oferuje dwa mechanizmy budowania relacji — odwoływanie się i osadzanie . Jak sama nazwa wskazuje, przy odwoływaniu się, MongoDB przechowuje powiązane dane jako oddzielny dokument w tej samej lub innej kolekcji i po prostu odwołuje się do nich za pomocą swojego identyfikatora.

Wręcz przeciwnie, w przypadku osadzania MongoDB przechowuje, a raczej osadza relację w samym dokumencie nadrzędnym.

Zobaczmy, jak możemy je wykorzystać. Zacznijmy od osadzenia Wydawcy w naszej książce :

@Embedded
private Publisher publisher;

Wystarczająco proste. Teraz przejdźmy dalej i dodajmy odniesienia do innych książek:

@Reference
private List<Book> companionBooks;

To wszystko — Morphia zapewnia wygodne adnotacje do relacji modelowych obsługiwanych przez MongoDB. Wybór odwoływania się do osadzania powinien jednak opierać się na złożoności, nadmiarowości i spójności modelu danych między innymi.

Ćwiczenie jest podobne do normalizacji w relacyjnych bazach danych.

Teraz jesteśmy gotowi do wykonania niektórych operacji na Książce za pomocą Datastore .

6. Niektóre podstawowe operacje

Zobaczmy, jak pracować z niektórymi podstawowymi operacjami przy użyciu Morphii.

6.1. Zapisz

Zacznijmy od najprostszej operacji, tworząc instancję Książka w naszej bibliotece bazy danych MongoDB :

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);

To wystarczy, aby Morphia stworzyła kolekcję w naszej bazie danych MongoDB, jeśli nie istnieje, i wykonała operację upsert.

6.2. Zapytanie

Zobaczmy, czy jesteśmy w stanie wysłać zapytanie do książki, którą właśnie utworzyliśmy w MongoDB:

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

assertEquals(1, books.size());

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

Zapytanie o dokument w Morphii zaczyna się od utworzenia zapytania za pomocą Datastore a następnie deklaratywnie dodajemy filtry, ku uciesze miłośników programowania funkcjonalnego!

Morphia obsługuje znacznie bardziej złożone konstrukcje zapytań z filtrami i operatorami. Ponadto Morphia umożliwia ograniczanie, pomijanie i porządkowanie wyników w zapytaniu.

Co więcej, Morphia pozwala nam używać surowych zapytań napisanych za pomocą sterownika Java dla MongoDB, aby uzyskać większą kontrolę, jeśli zajdzie taka potrzeba.

6.3. Zaktualizuj

Chociaż operacja zapisywania może obsługiwać aktualizacje, jeśli klucz podstawowy jest zgodny, Morphia zapewnia sposoby selektywnego aktualizowania dokumentów:

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());

W tym miejscu tworzymy zapytanie i operację aktualizacji, aby zwiększyć o jeden cenę wszystkich książek zwróconych przez zapytanie.

6.4. Usuń

Wreszcie to, co zostało stworzone, musi zostać usunięte! Ponownie, w przypadku Morphii jest to dość intuicyjne:

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());

Tworzymy zapytanie w podobny sposób jak poprzednio i uruchamiamy operację usuwania w Datastore .

7. Zaawansowane użycie

MongoDB ma niektóre zaawansowane operacje, takie jak agregacja, indeksowanie i wiele innych . Chociaż nie jest możliwe wykonanie tego wszystkiego za pomocą Morphii, z pewnością można to osiągnąć. W przypadku innych niestety będziemy musieli wrócić do sterownika Java dla MongoDB.

Skoncentrujmy się na niektórych z tych zaawansowanych operacji, które możemy wykonać za pomocą Morphii.

7.1. Agregacja

Agregacja w MongoDB pozwala nam zdefiniować serię operacji w potoku, który może operować na zestawie dokumentów i generować zagregowane dane wyjściowe .

Morphia ma API do obsługi takiego potoku agregacji.

Załóżmy, że chcemy agregować nasze dane biblioteczne w taki sposób, aby wszystkie książki były pogrupowane według ich autorów:

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

Jak to działa? Zaczynamy od utworzenia potoku agregacji przy użyciu tego samego starego Datastore . Musimy podać podmiot, na którym chcemy wykonać operacje agregacji, na przykład Book tutaj.

Następnie chcemy pogrupować dokumenty według „autora” i zagregować ich „tytuł” ​​pod kluczem o nazwie „książki”. Wreszcie pracujemy tutaj z ODM. Dlatego musimy zdefiniować podmiot do zbierania naszych danych zagregowanych — w naszym przypadku jest to Autor .

Oczywiście musimy zdefiniować podmiot o nazwie Autor ze zmienną o nazwie książki:

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

To oczywiście tylko zarysowuje powierzchnię bardzo potężnej konstrukcji dostarczonej przez MongoDB i można ją dokładniej zbadać.

7.2. Projekcja

Projekcja w MongoDB pozwala nam wybrać tylko te pola, które chcemy pobrać z dokumentów w naszych zapytaniach . Jeśli struktura dokumentu jest złożona i ciężka, może to być naprawdę przydatne, gdy potrzebujemy tylko kilku pól.

Załóżmy, że w zapytaniu musimy pobrać tylko książki z ich tytułami:

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());

Tutaj, jak widzimy, zwracamy tylko tytuł w naszym wyniku, a nie autora i inne pola. Powinniśmy jednak być ostrożni przy używaniu przewidywanych wyników do zapisywania z powrotem do MongoDB. Może to spowodować utratę danych!

7.3. Indeksowanie

Indeksy odgrywają bardzo ważną rolę w optymalizacji zapytań w bazach danych — relacyjnych oraz wielu nierelacyjnych.

MongoDB definiuje indeksy na poziomie kolekcji z unikalnym indeksem tworzonym domyślnie na kluczu podstawowym . Ponadto MongoDB umożliwia tworzenie indeksów na dowolnym polu lub podpolu w dokumencie. Powinniśmy wybrać utworzenie indeksu na kluczu w zależności od zapytania, które chcemy utworzyć.

Na przykład w naszym przykładzie możemy chcieć utworzyć indeks w polu „tytuł” ​​Książki ponieważ często kończymy na tym pytaniu:

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

Oczywiście możemy przekazać dodatkowe opcje indeksowania, aby dostosować niuanse tworzonego indeksu. Pamiętaj, że pole powinno mieć adnotację @Właściwość do wykorzystania w indeksie.

Co więcej, oprócz indeksu na poziomie klasy, Morphia ma również adnotację do zdefiniowania indeksu na poziomie pola.

7.4. Weryfikacja schematu

Mamy opcję zapewnienia reguł sprawdzania poprawności danych dla kolekcji, z których MongoDB może korzystać podczas wykonywania operacji aktualizacji lub wstawiania . Morphia wspiera to poprzez swoje API.

Powiedzmy, że nie chcemy wstawiać książki bez prawidłowej ceny. Aby to osiągnąć, możemy wykorzystać walidację schematu:

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

Istnieje bogaty zestaw walidacji dostarczonych przez MongoDB, które można tutaj zastosować.

8. Alternatywne ODM MongoDB

Morphia nie jest jedynym dostępnym MongoDB ODM dla Javy. Istnieje kilka innych, które możemy rozważyć w naszych aplikacjach. Dyskusja na temat porównania z Morphią nie jest tutaj możliwa, ale zawsze warto znać nasze opcje:

  • Spring Data:zapewnia model programowania oparty na Springu do pracy z MongoDB
  • MongoJack:zapewnia bezpośrednie mapowanie z obiektów JSON na obiekty MongoDB

To nie jest pełna lista ODM MongoDB dla Javy, ale dostępnych jest kilka interesujących alternatyw!


No
  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Czy muszę ręcznie zamknąć połączenie z mangustą?

  2. Jak mogę wyłączyć komunikaty dziennika MongoDB w konsoli?

  3. mongodb 3.4.3 Odmowa uprawnień błąd 267 wiredtiger_kv_engine.cpp z ubuntu 16

  4. Utwórz klaster baz danych w chmurze za pomocą MongoDB Atlas

  5. Pomnóż pole przez wartość w Mongodb