MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Einführung in Morphia – Java ODM für MongoDB

1. Übersicht

In diesem Tutorial werden wir verstehen, wie man Morphia, einen Object Document Mapper (ODM) für MongoDB in Java verwendet.

Dabei werden wir auch verstehen, was ein ODM ist und wie es die Arbeit mit MongoDB erleichtert.

2. Was ist ein ODM ?

Für diejenigen, die in diesem Bereich nicht eingeweiht sind, MongoDB ist eine dokumentenorientierte Datenbank, die von Natur aus für die Verbreitung entwickelt wurde . Dokumentorientierte Datenbanken verwalten, einfach ausgedrückt, Dokumente, die nichts anderes sind als eine schemalose Art, halbstrukturierte Daten zu organisieren . Sie fallen unter ein breiteres und locker definiertes Dach von NoSQL-Datenbanken, benannt nach ihrer offensichtlichen Abkehr von der traditionellen Organisation von SQL-Datenbanken.

MongoDB bietet Treiber für fast alle gängigen Programmiersprachen wie Java . Diese Treiber bieten eine Abstraktionsebene für die Arbeit mit MongoDB, sodass wir nicht direkt mit Wire Protocol arbeiten. Betrachten Sie dies als Oracle, das eine Implementierung des JDBC-Treibers für seine relationale Datenbank bereitstellt.

Wenn wir uns jedoch an unsere Tage erinnern, als wir direkt mit JDBC gearbeitet haben, können wir erkennen, wie chaotisch es werden kann – insbesondere in einem objektorientierten Paradigma. Glücklicherweise haben wir Object Relational Mapping (ORM)-Frameworks wie Hibernate zu unserer Rettung. Bei MongoDB ist das nicht viel anders.

Während wir sicherlich mit dem Low-Level-Treiber arbeiten können, erfordert es viel mehr Boilerplate, um die Aufgabe zu erfüllen. Hier haben wir ein ähnliches Konzept wie ORM namens Object Document Mapper (ODM) . Morphia füllt genau diesen Raum für die Programmiersprache Java aus und arbeitet auf dem Java-Treiber für MongoDB.

3. Abhängigkeiten einrichten

Wir haben genug Theorie gesehen, um uns in einen Code einzuarbeiten. Für unsere Beispiele werden wir eine Bücherbibliothek modellieren und sehen, wie wir sie in MongoDB mit Morphia verwalten können.

Aber bevor wir beginnen, müssen wir einige der Abhängigkeiten einrichten.

3.1. MongoDB

Wir benötigen eine laufende Instanz von MongoDB, mit der wir arbeiten können. Es gibt mehrere Möglichkeiten, dies zu erhalten, und die einfachste ist, die Community-Edition herunterzuladen und auf unserem lokalen Computer zu installieren.

Wir sollten alle Standardkonfigurationen unverändert lassen, einschließlich des Ports, auf dem MongoDB ausgeführt wird.

3.2. Morphia

Wir können die vorgefertigten JARs für Morphia von Maven Central herunterladen und sie in unserem Java-Projekt verwenden.

Der einfachste Weg ist jedoch die Verwendung eines Abhängigkeitsverwaltungstools wie Maven:

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

4. Wie verbinde ich mich mit Morphia?

Nachdem wir nun MongoDB installiert und ausgeführt und Morphia in unserem Java-Projekt eingerichtet haben, können wir mithilfe von Morphia eine Verbindung zu MongoDB herstellen.

Mal sehen, wie wir das erreichen können:

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

Das wars so ziemlich! Lassen Sie uns das besser verstehen. Wir brauchen zwei Dinge, damit unsere Mapping-Operationen funktionieren:

  1. Ein Mapper:Dieser ist für die Zuordnung unserer Java-POJOs zu MongoDB-Sammlungen verantwortlich . In unserem Code-Snippet oben, Morphia Dafür ist die Klasse zuständig. Beachten Sie, wie wir das Paket konfigurieren, wo es nach unseren POJOs suchen soll.
  2. Eine Verbindung:Dies ist die Verbindung zu einer MongoDB-Datenbank, auf der der Mapper verschiedene Operationen ausführen kann. Die Klasse Datenspeicher nimmt als Parameter eine Instanz von MongoClient (aus dem Java MongoDB-Treiber) und dem Namen der MongoDB-Datenbank, gibt eine aktive Verbindung zurück, mit der gearbeitet werden kann .

Wir sind also bereit, diesen Datenspeicher zu verwenden und mit unseren Einheiten zusammenarbeiten.

5. Wie arbeite ich mit Entitäten?

Bevor wir unseren frisch gebackenen Datenspeicher verwenden können , müssen wir einige Domänenentitäten definieren, mit denen wir arbeiten können.

5.1. Einfache Entität

Beginnen wir mit der Definition eines einfachen Buchs Entität mit einigen Attributen:

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

Hier sind ein paar interessante Dinge zu beachten:

  • Beachten Sie die Anmerkung @Entität die dieses POJO für die ODM-Zuordnung qualifiziert von Morphia
  • Morphia ordnet eine Entität standardmäßig einer Sammlung in MongoDB nach dem Namen ihrer Klasse zu, aber wir können dies explizit überschreiben (wie wir es für die Entität Book getan haben hier)
  • Morphia ordnet standardmäßig die Variablen in einer Entität den Schlüsseln in einer MongoDB-Sammlung nach dem Namen der Variablen zu, aber auch hier können wir dies überschreiben (wie wir es für die Variable Kosten hier)
  • Zuletzt müssen wir eine Variable in der Entität mit der Annotation @Id markieren, die als Primärschlüssel fungiert (als würden wir hier die ISBN für unser Buch verwenden)

5.2. Entitäten mit Beziehungen

In der realen Welt sind Entitäten jedoch kaum so einfach, wie sie aussehen, und haben komplexe Beziehungen zueinander. Zum Beispiel unsere einfache Entität Book kann einen Publisher haben und kann auf andere Begleitbücher verweisen. Wie modellieren wir sie?

MongoDB bietet zwei Mechanismen zum Aufbau von Beziehungen – Verweisen und Einbetten . Wie der Name schon sagt, speichert MongoDB bei der Referenzierung verwandte Daten als separates Dokument in derselben oder einer anderen Sammlung und referenziert sie einfach mit ihrer ID.

Im Gegensatz dazu speichert bzw. bettet MongoDB beim Einbetten die Relation innerhalb des übergeordneten Dokuments selbst ein.

Mal sehen, wie wir sie verwenden können. Beginnen wir mit dem Einbetten von Publisher in unserem Buch :

@Embedded
private Publisher publisher;

Einfach genug. Lassen Sie uns jetzt fortfahren und Verweise auf andere Bücher hinzufügen:

@Reference
private List<Book> companionBooks;

Das war’s – Morphia bietet bequeme Anmerkungen zum Modellieren von Beziehungen, wie sie von MongoDB unterstützt werden. Die Wahl zwischen Referenzierung und Einbettung sollte sich jedoch auf die Komplexität, Redundanz und Konsistenz des Datenmodells stützen unter anderem.

Die Übung ähnelt der Normalisierung in relationalen Datenbanken.

Jetzt sind wir bereit, einige Vorgänge für Book auszuführen mit Datenspeicher .

6. Einige grundlegende Operationen

Lassen Sie uns sehen, wie man mit einigen der grundlegenden Operationen arbeitet, die Morphia verwenden.

6.1. Speichern

Beginnen wir mit der einfachsten Operation, dem Erstellen einer Instanz von Book in unserer MongoDB-Datenbank Bibliothek :

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

Dies reicht aus, um Morphia eine Sammlung in unserer MongoDB-Datenbank erstellen zu lassen, falls diese nicht existiert, und eine Upsert-Operation durchzuführen.

6.2. Abfrage

Mal sehen, ob wir das gerade erstellte Buch in MongoDB abfragen können:

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

assertEquals(1, books.size());

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

Das Abfragen eines Dokuments in Morphia beginnt mit dem Erstellen einer Abfrage unter Verwendung von Datastore und dann deklarativ Filter hinzufügen, zur Freude derer, die in funktionale Programmierung verliebt sind!

Morphia unterstützt viel komplexere Abfragekonstruktionen mit Filtern und Operatoren. Darüber hinaus ermöglicht Morphia das Einschränken, Überspringen und Sortieren von Ergebnissen in der Abfrage.

Darüber hinaus ermöglicht uns Morphia die Verwendung von Rohabfragen, die mit dem Java-Treiber für MongoDB geschrieben wurden, für mehr Kontrolle, falls dies erforderlich sein sollte.

6.3. Aktualisieren

Obwohl eine Speicheroperation Aktualisierungen handhaben kann, wenn der Primärschlüssel übereinstimmt, bietet Morphia Möglichkeiten, Dokumente selektiv zu aktualisieren:

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

Hier erstellen wir eine Abfrage und einen Aktualisierungsvorgang, um den Preis aller von der Abfrage zurückgegebenen Bücher um eins zu erhöhen.

6.4. Löschen

Abschließend muss das Erschaffene gelöscht werden! Auch hier ist es mit Morphia recht intuitiv:

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

Wir erstellen die Abfrage ganz ähnlich wie zuvor und führen den Löschvorgang auf dem Datenspeicher aus .

7. Erweiterte Nutzung

MongoDB verfügt über einige erweiterte Operationen wie Aggregation, Indizierung und viele andere . Es ist zwar nicht möglich, all das mit Morphia durchzuführen, aber es ist sicherlich möglich, einiges davon zu erreichen. Für andere müssen wir leider auf den Java-Treiber für MongoDB zurückgreifen.

Konzentrieren wir uns auf einige dieser fortgeschrittenen Operationen, die wir mit Morphia durchführen können.

7.1. Aggregation

Die Aggregation in MongoDB ermöglicht es uns, eine Reihe von Vorgängen in einer Pipeline zu definieren, die auf einer Reihe von Dokumenten ausgeführt werden und eine aggregierte Ausgabe erzeugen können .

Morphia verfügt über eine API zur Unterstützung einer solchen Aggregationspipeline.

Nehmen wir an, wir möchten unsere Bibliotheksdaten so aggregieren, dass wir alle Bücher nach ihrem Autor gruppiert haben:

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

Also, wie funktioniert das? Wir beginnen mit der Erstellung einer Aggregationspipeline unter Verwendung desselben alten Datenspeichers . Wir müssen die Entität angeben, für die wir Aggregationsvorgänge durchführen möchten, z. B. Book hier.

Als nächstes wollen wir Dokumente nach „Autor“ gruppieren und ihren „Titel“ unter einem Schlüssel namens „Bücher“ zusammenfassen. Schließlich arbeiten wir hier mit einem ODM. Wir müssen also eine Entität definieren, um unsere aggregierten Daten zu sammeln – in unserem Fall ist es Autor .

Natürlich müssen wir eine Entität namens Author definieren mit einer Variablen namens books:

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

Dies kratzt natürlich nur an der Oberfläche eines sehr leistungsfähigen Konstrukts, das von MongoDB bereitgestellt wird und für Details weiter untersucht werden kann.

7.2. Projektion

Projektion in MongoDB ermöglicht es uns, nur die Felder auszuwählen, die wir aus Dokumenten in unseren Abfragen abrufen möchten . Falls die Dokumentstruktur komplex und schwer ist, kann dies sehr nützlich sein, wenn wir nur wenige Felder benötigen.

Nehmen wir an, wir brauchen in unserer Abfrage nur Bücher mit ihrem Titel abzurufen:

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

Wie wir sehen, bekommen wir hier in unserem Ergebnis nur den Titel zurück und nicht den Autor und andere Felder. Wir sollten jedoch vorsichtig sein, wenn wir die projizierte Ausgabe beim Zurückspeichern in MongoDB verwenden. Dies kann zu Datenverlust führen!

7.3. Indizierung

Indizes spielen eine sehr wichtige Rolle bei der Abfrageoptimierung mit Datenbanken – sowohl relationale als auch viele nicht-relationale.

MongoDB definiert Indizes auf Sammlungsebene mit einem eindeutigen Index, der standardmäßig auf dem Primärschlüssel erstellt wird . Darüber hinaus ermöglicht MongoDB die Erstellung von Indizes für jedes Feld oder Unterfeld innerhalb eines Dokuments. Wir sollten uns entscheiden, einen Index für einen Schlüssel zu erstellen, abhängig von der Abfrage, die wir erstellen möchten.

In unserem Beispiel möchten wir beispielsweise einen Index für das Feld „Titel“ von Buch erstellen da wir am Ende oft danach fragen:

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

Natürlich können wir zusätzliche Indizierungsoptionen übergeben, um die Nuancen des erstellten Index anzupassen. Beachten Sie, dass das Feld mit @Property kommentiert werden sollte in einem Index verwendet werden.

Darüber hinaus hat Morphia neben dem Index auf Klassenebene auch eine Anmerkung, um einen Index auf Feldebene zu definieren.

7.4. Schemavalidierung

Wir haben eine Option zum Bereitstellen von Datenvalidierungsregeln für eine Sammlung, die MongoDB beim Ausführen eines Aktualisierungs- oder Einfügevorgangs verwenden kann . Morphia unterstützt dies durch seine APIs.

Angenommen, wir möchten kein Buch ohne gültigen Preis einfügen. Wir können die Schemavalidierung nutzen, um dies zu erreichen:

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

Es gibt eine Vielzahl von Validierungen, die von MongoDB bereitgestellt werden und hier verwendet werden können.

8. Alternative MongoDB-ODMs

Morphia ist nicht das einzige verfügbare MongoDB-ODM für Java. Es gibt mehrere andere, die wir in unseren Anwendungen verwenden können. Eine Diskussion über den Vergleich mit Morphia ist hier nicht möglich, aber es ist immer nützlich, unsere Möglichkeiten zu kennen:

  • Spring Data:Stellt ein Spring-basiertes Programmiermodell für die Arbeit mit MongoDB bereit
  • MongoJack:Bietet direkte Zuordnung von JSON zu MongoDB-Objekten

Dies ist keine vollständige Liste der MongoDB-ODMs für Java, aber es sind einige interessante Alternativen verfügbar!


No