sql >> Database >  >> NoSQL >> MongoDB

Inleiding tot Morphia - Java ODM voor MongoDB

1. Overzicht

In deze tutorial zullen we begrijpen hoe we Morphia, een Object Document Mapper (ODM) voor MongoDB in Java kunnen gebruiken.

Tijdens het proces zullen we ook begrijpen wat een ODM is en hoe het het werken met MongoDB vergemakkelijkt.

2. Wat is een ODM ?

Voor degenen die niet zijn ingewijd op dit gebied:MongoDB is een documentgeoriënteerde database die is gebouwd om door de natuur te worden gedistribueerd . Documentgeoriënteerde databases beheren, in eenvoudige bewoordingen, documenten die niets anders zijn dan een schemaloze manier om semi-gestructureerde gegevens te organiseren . Ze vallen onder een bredere en losjes gedefinieerde paraplu van NoSQL-databases, genoemd naar hun kennelijke vertrek uit de traditionele organisatie van SQL-databases.

MongoDB biedt stuurprogramma's voor bijna alle populaire programmeertalen zoals Java . Deze stuurprogramma's bieden een abstractielaag voor het werken met MongoDB, zodat we niet rechtstreeks met Wire Protocol werken. Zie dit als Oracle die een implementatie levert van het JDBC-stuurprogramma voor hun relationele database.

Als we echter terugdenken aan onze dagen dat we rechtstreeks met JDBC werkten, kunnen we begrijpen hoe rommelig het kan worden, vooral in een objectgeoriënteerd paradigma. Gelukkig hebben we Object Relational Mapping (ORM)-frameworks zoals Hibernate ons te hulp. Het is niet heel anders voor MongoDB.

Hoewel we zeker met de low-level driver kunnen werken, is er veel meer standaardwerk nodig om de taak te volbrengen. Hier hebben we een soortgelijk concept als ORM genaamd Object Document Mapper (ODM) . Morphia vult precies die ruimte voor de Java-programmeertaal en werkt bovenop de Java-driver voor MongoDB.

3. Afhankelijkheden instellen

We hebben genoeg theorie gezien om ons in een code te krijgen. Voor onze voorbeelden zullen we een bibliotheek met boeken modelleren en kijken hoe we deze in MongoDB kunnen beheren met Morphia.

Maar voordat we beginnen, moeten we enkele afhankelijkheden instellen.

3.1. MongoDB

We hebben een actieve instantie van MongoDB nodig om mee te werken. Er zijn verschillende manieren om dit te krijgen, en de eenvoudigste is om de community-editie te downloaden en te installeren op onze lokale computer.

We moeten alle standaardconfiguraties ongewijzigd laten, inclusief de poort waarop MongoDB draait.

3.2. Morphia

We kunnen de vooraf gebouwde JAR's voor Morphia downloaden van Maven Central en ze gebruiken in ons Java-project.

De eenvoudigste manier is echter om een ​​hulpprogramma voor afhankelijkheidsbeheer zoals Maven te gebruiken:

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

4. Hoe verbinding maken met Morphia?

Nu we MongoDB hebben geïnstalleerd en draaien en Morphia hebben ingesteld in ons Java-project, zijn we klaar om verbinding te maken met MongoDB met behulp van Morphia.

Laten we eens kijken hoe we dat kunnen bereiken:

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

Dat is het eigenlijk wel! Laten we dit beter begrijpen. We hebben twee dingen nodig om onze kaartbewerkingen te laten werken:

  1. Een mapper:deze is verantwoordelijk voor het toewijzen van onze Java-POJO's aan MongoDB-verzamelingen . In ons codefragment hierboven, Morphia is de klasse die daarvoor verantwoordelijk is. Merk op hoe we het pakket configureren waar het moet zoeken naar onze POJO's.
  2. Een verbinding:dit is de verbinding met een MongoDB-database waarop de mapper verschillende bewerkingen kan uitvoeren. De klasse Datastore neemt als parameter een instantie van MongoClient (van het Java MongoDB-stuurprogramma) en de naam van de MongoDB-database, het retourneren van een actieve verbinding om mee te werken .

We zijn er dus helemaal klaar voor om deze Datastore te gebruiken en werk samen met onze entiteiten.

5. Hoe te werken met entiteiten?

Voordat we onze vers geslagen Datastore kunnen gebruiken , moeten we enkele domeinentiteiten definiëren om mee te werken.

5.1. Eenvoudige entiteit

Laten we beginnen met het definiëren van een eenvoudig Boek entiteit met enkele 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
}

Er zijn een paar interessante dingen om op te merken:

  • Let op de annotatie @Entiteit die deze POJO kwalificeert voor ODM-mapping door Morphia
  • Morphia wijst standaard een entiteit toe aan een verzameling in MongoDB met de naam van zijn klasse, maar we kunnen dit expliciet negeren (zoals we hebben gedaan voor de entiteit Boek hier)
  • Morphia wijst standaard de variabelen in een entiteit toe aan de sleutels in een MongoDB-verzameling met de naam van de variabele, maar nogmaals, we kunnen dit overschrijven (zoals we hebben gedaan voor de variabele kosten hier)
  • Ten slotte moeten we een variabele in de entiteit markeren om als primaire sleutel te fungeren met de annotatie @Id (alsof we hier ISBN voor ons boek gebruiken)

5.2. Entiteiten met relaties

In de echte wereld zijn entiteiten echter niet zo eenvoudig als ze eruitzien en hebben ze complexe relaties met elkaar. Bijvoorbeeld, onze eenvoudige entiteit Boek kan een Uitgever . hebben en kan verwijzen naar andere begeleidende boeken. Hoe modelleren we ze?

MongoDB biedt twee mechanismen om relaties op te bouwen:verwijzen en insluiten . Zoals de naam al doet vermoeden, slaat MongoDB met verwijzingen gerelateerde gegevens op als een afzonderlijk document in dezelfde of een andere verzameling en verwijst ernaar met behulp van zijn id.

Integendeel, met inbedding slaat MongoDB de relatie op in het bovenliggende document zelf, of liever gezegd ingesloten.

Laten we eens kijken hoe we ze kunnen gebruiken. Laten we beginnen met het insluiten van Uitgever in ons Boek :

@Embedded
private Publisher publisher;

Simpel genoeg. Laten we nu verder gaan en verwijzingen naar andere boeken toevoegen:

@Reference
private List<Book> companionBooks;

Dat is het - Morphia biedt handige annotaties om relaties te modelleren zoals ondersteund door MongoDB. De keuze voor verwijzing versus inbedding moet echter gebaseerd zijn op de complexiteit, redundantie en consistentie van datamodellen onder andere.

De oefening is vergelijkbaar met normalisatie in relationele databases.

Nu zijn we klaar om enkele bewerkingen uit te voeren op Boek met behulp van Datastore .

6. Enkele basishandelingen

Laten we eens kijken hoe we met enkele van de basisbewerkingen kunnen werken met Morphia.

6.1. Opslaan

Laten we beginnen met de eenvoudigste van de bewerkingen, het maken van een instantie van Boek in onze MongoDB-database bibliotheek :

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

Dit is voldoende om Morphia een collectie te laten maken in onze MongoDB-database, als deze niet bestaat, en een upsert-bewerking uit te voeren.

6.2. Zoekopdracht

Laten we eens kijken of we het boek kunnen opvragen dat we zojuist in MongoDB hebben gemaakt:

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

assertEquals(1, books.size());

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

Het opvragen van een document in Morphia begint met het maken van een zoekopdracht met behulp van Datastore en vervolgens declaratief filters toe te voegen, tot grote vreugde van degenen die verliefd zijn op functioneel programmeren!

Morphia ondersteunt veel complexere queryconstructie met filters en operators. Bovendien maakt Morphia het mogelijk om resultaten in de zoekopdracht te beperken, over te slaan en te ordenen.

Bovendien stelt Morphia ons in staat om onbewerkte queries te gebruiken die zijn geschreven met de Java-driver voor MongoDB voor meer controle, mocht dat nodig zijn.

6.3. Bijwerken

Hoewel een opslagbewerking updates kan verwerken als de primaire sleutel overeenkomt, biedt Morphia manieren om documenten selectief bij te werken:

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 bouwen we een zoekopdracht en een updatebewerking om de prijs van alle boeken die door de zoekopdracht worden geretourneerd, met één te verhogen.

6.4. Verwijderen

Ten slotte moet wat is gemaakt, worden verwijderd! Nogmaals, met Morphia is het vrij intuïtief:

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

We maken de query op dezelfde manier als voorheen en voeren de verwijderbewerking uit op de Datastore .

7. Geavanceerd gebruik

MongoDB heeft enkele geavanceerde bewerkingen zoals aggregatie, indexering en vele andere . Hoewel het niet mogelijk is om dat allemaal uit te voeren met Morphia, is het zeker mogelijk om een ​​deel daarvan te bereiken. Voor anderen moeten we helaas terugvallen op de Java-driver voor MongoDB.

Laten we ons concentreren op enkele van deze geavanceerde bewerkingen die we via Morphia kunnen uitvoeren.

7.1. Aggregatie

Aggregatie in MongoDB stelt ons in staat om een reeks bewerkingen in een pijplijn te definiëren die op een set documenten kunnen werken en geaggregeerde uitvoer kunnen produceren .

Morphia heeft een API om zo'n aggregatiepijplijn te ondersteunen.

Laten we aannemen dat we onze bibliotheekgegevens zo willen samenvoegen dat we alle boeken gegroepeerd hebben op hun auteur:

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

Dus, hoe werkt dit? We beginnen met het maken van een aggregatiepijplijn met dezelfde oude Datastore . We moeten de entiteit opgeven waarop we aggregatiebewerkingen willen uitvoeren, bijvoorbeeld Boek hier.

Vervolgens willen we documenten groeperen op "auteur" en hun "titel" samenvoegen onder een sleutel genaamd "boeken". Ten slotte werken we hier met een ODM. We moeten dus een entiteit definiëren om onze geaggregeerde gegevens te verzamelen - in ons geval is dit Auteur .

Natuurlijk moeten we een entiteit definiëren met de naam Auteur met een variabele genaamd books:

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

Dit is natuurlijk slechts het begin van een zeer krachtige constructie van MongoDB en kan verder worden onderzocht voor details.

7.2. Projectie

Met projectie in MongoDB kunnen we alleen de velden selecteren die we willen ophalen uit documenten in onze zoekopdrachten . Als de documentstructuur complex en zwaar is, kan dit erg handig zijn als we maar een paar velden nodig hebben.

Laten we aannemen dat we alleen boeken met hun titel hoeven op te halen in onze zoekopdracht:

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

Hier krijgen we, zoals we kunnen zien, alleen de titel terug in ons resultaat en niet de auteur en andere velden. We moeten echter voorzichtig zijn bij het gebruik van de geprojecteerde uitvoer bij het terug opslaan naar MongoDB. Dit kan leiden tot gegevensverlies!

7.3. Indexeren

Indexen spelen een zeer belangrijke rol bij het optimaliseren van zoekopdrachten met databases — zowel relationele als vele niet-relationele.

MongoDB definieert indexen op het niveau van de verzameling met een unieke index die standaard op de primaire sleutel wordt gemaakt . Bovendien maakt MongoDB het mogelijk om indexen te maken op elk veld of subveld binnen een document. We moeten ervoor kiezen om een ​​index op een sleutel te maken, afhankelijk van de query die we willen maken.

In ons voorbeeld willen we bijvoorbeeld een index maken op het veld "titel" van Boek omdat we er vaak vragen over stellen:

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

Natuurlijk kunnen we aanvullende indexeringsopties doorgeven om de nuances van de index die wordt gemaakt aan te passen. Merk op dat het veld moet worden geannoteerd door @Eigenschap te gebruiken in een index.

Bovendien heeft Morphia, afgezien van de index op klasseniveau, een annotatie om ook een index op veldniveau te definiëren.

7.4. Schemavalidatie

We hebben een optie om gegevensvalidatieregels te bieden voor een verzameling die MongoDB kan gebruiken tijdens het uitvoeren van een update- of invoegbewerking . Morphia ondersteunt dit via hun API's.

Laten we zeggen dat we geen boek willen invoegen zonder een geldige prijs. We kunnen schemavalidatie gebruiken om dit te bereiken:

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

Er is een uitgebreide reeks validaties geleverd door MongoDB die hier kan worden gebruikt.

8. Alternatieve MongoDB ODM's

Morphia is niet de enige beschikbare MongoDB ODM voor Java. Er zijn verschillende andere die we kunnen overwegen om in onze toepassingen te gebruiken. Een discussie over vergelijking met Morphia is hier niet mogelijk, maar het is altijd handig om onze opties te kennen:

  • Spring Data:biedt een op Spring gebaseerd programmeermodel voor het werken met MongoDB
  • MongoJack:biedt directe toewijzing van JSON naar MongoDB-objecten

Dit is geen volledige lijst van MongoDB ODM's voor Java, maar er zijn enkele interessante alternatieven beschikbaar!


  1. Mongoose selecteert velden om terug te keren van findOneAndUpdate

  2. Spring Boot en hoe verbindingsdetails met MongoDB te configureren?

  3. Mongod klaagt dat er geen map /data/db is

  4. Transactie-ondersteuning in MongoDB