MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Introduction à Morphia – Java ODM pour MongoDB

1. Présentation

Dans ce tutoriel, nous allons comprendre comment utiliser Morphia, un Object Document Mapper (ODM) pour MongoDB en Java.

Au cours du processus, nous comprendrons également ce qu'est un ODM et comment il facilite le travail avec MongoDB.

2. Qu'est-ce qu'un ODM ?

Pour les non-initiés dans ce domaine, MongoDB est une base de données orientée document conçue pour être distribuée par nature . Les bases de données orientées documents, en termes simples, gèrent des documents, qui ne sont rien d'autre qu'un moyen sans schéma d'organiser des données semi-structurées . Elles relèvent d'un ensemble plus large et vaguement défini de bases de données NoSQL, du nom de leur apparente rupture par rapport à l'organisation traditionnelle des bases de données SQL.

MongoDB fournit des pilotes pour presque tous les langages de programmation populaires comme Java . Ces pilotes offrent une couche d'abstraction pour travailler avec MongoDB afin que nous ne travaillions pas directement avec Wire Protocol. Considérez cela comme Oracle fournissant une implémentation du pilote JDBC pour leur base de données relationnelle.

Cependant, si nous nous souvenons de nos journées de travail avec JDBC directement, nous pouvons apprécier à quel point cela peut devenir désordonné, en particulier dans un paradigme orienté objet. Heureusement, nous avons des frameworks ORM (Object Relational Mapping) comme Hibernate à notre secours. Ce n'est pas très différent pour MongoDB.

Bien que nous puissions certainement travailler avec le pilote de bas niveau, cela nécessite beaucoup plus de passe-partout pour accomplir la tâche. Ici, nous avons un concept similaire à ORM appelé Object Document Mapper (ODM) . Morphia remplit exactement cet espace pour le langage de programmation Java et fonctionne au-dessus du pilote Java pour MongoDB.

3. Configuration des dépendances

Nous avons vu assez de théorie pour entrer dans du code. Pour nos exemples, nous allons modéliser une bibliothèque de livres et voir comment nous pouvons la gérer dans MongoDB en utilisant Morphia.

Mais avant de commencer, nous devrons configurer certaines des dépendances.

3.1. MongoDB

Nous avons besoin d'une instance en cours d'exécution de MongoDB pour travailler avec. Il existe plusieurs façons d'obtenir cela, et le plus simple est de télécharger et d'installer l'édition communautaire sur notre ordinateur local.

Nous devrions laisser toutes les configurations par défaut telles quelles, y compris le port sur lequel MongoDB s'exécute.

3.2. Morphie

Nous pouvons télécharger les fichiers JAR pré-construits pour Morphia depuis Maven Central et les utiliser dans notre projet Java.

Cependant, le plus simple est d'utiliser un outil de gestion des dépendances comme Maven :

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

4. Comment se connecter avec Morphia ?

Maintenant que MongoDB est installé et en cours d'exécution et que nous avons configuré Morphia dans notre projet Java, nous sommes prêts à nous connecter à MongoDB à l'aide de Morphia.

Voyons comment nous pouvons y parvenir :

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

C'est à peu près tout ! Comprenons mieux cela. Nous avons besoin de deux choses pour que nos opérations de cartographie fonctionnent :

  1. Un mappeur :il est chargé de mapper nos POJO Java sur les collections MongoDB . Dans notre extrait de code ci-dessus, Morphia est la classe responsable de cela. Notez comment nous configurons le package où il doit rechercher nos POJO.
  2. Une connexion :il s'agit de la connexion à une base de données MongoDB sur laquelle le mappeur peut exécuter différentes opérations. La classe Datastore prend en paramètre une instance de MongoClient (du pilote Java MongoDB) et le nom de la base de données MongoDB, renvoyant une connexion active avec laquelle travailler .

Donc, nous sommes tous prêts à utiliser ce Datastore et travaillez avec nos entités.

5. Comment travailler avec des entités ?

Avant de pouvoir utiliser notre nouveau Datastore , nous devons définir certaines entités de domaine avec lesquelles travailler.

5.1. Entité simple

Commençons par définir un livre simple entité avec certains attributs :

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

Il y a quelques choses intéressantes à noter ici :

  • Remarquez l'annotation @Entité qui qualifie ce POJO pour le mappage ODM par Morphie
  • Morphia, par défaut, mappe une entité à une collection dans MongoDB par le nom de sa classe, mais nous pouvons explicitement remplacer cela (comme nous l'avons fait pour l'entité Livre ici)
  • Morphia, par défaut, mappe les variables d'une entité aux clés d'une collection MongoDB par le nom de la variable, mais encore une fois, nous pouvons remplacer cela (comme nous l'avons fait pour la variable coût ici)
  • Enfin, nous devons marquer une variable dans l'entité pour qu'elle agisse comme clé primaire par l'annotation @Id (comme si nous utilisons l'ISBN pour notre livre ici)

5.2. Entités avec des relations

Dans le monde réel, cependant, les entités ne sont pas aussi simples qu'elles en ont l'air et entretiennent des relations complexes les unes avec les autres. Par exemple, notre simple entité Réserver peut avoir un éditeur et peut faire référence à d'autres livres d'accompagnement. Comment les modélisons-nous ?

MongoDB offre deux mécanismes pour établir des relations :le référencement et l'intégration . Comme son nom l'indique, avec le référencement, MongoDB stocke les données associées dans un document séparé dans la même collection ou dans une collection différente et les référence simplement à l'aide de son identifiant.

Au contraire, avec l'incorporation, MongoDB stocke ou plutôt intègre la relation dans le document parent lui-même.

Voyons comment nous pouvons les utiliser. Commençons par intégrer Publisher dans notre Livre :

@Embedded
private Publisher publisher;

Assez simple. Continuons maintenant et ajoutons des références à d'autres livres :

@Reference
private List<Book> companionBooks;

C'est tout - Morphia fournit des annotations pratiques pour modéliser les relations telles que prises en charge par MongoDB. Cependant, le choix du référencement par rapport à l'intégration doit s'appuyer sur la complexité, la redondance et la cohérence du modèle de données entre autres considérations.

L'exercice est similaire à la normalisation dans les bases de données relationnelles.

Maintenant, nous sommes prêts à effectuer quelques opérations sur Réserver en utilisant Datastore .

6. Quelques opérations de base

Voyons comment travailler avec certaines des opérations de base en utilisant Morphia.

6.1. Enregistrer

Commençons par la plus simple des opérations, en créant une instance de Livre dans notre base de données MongoDB bibliothèque :

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

Cela suffit pour laisser Morphia créer une collection dans notre base de données MongoDB, si elle n'existe pas, et effectuer une opération upsert.

6.2. Requête

Voyons si nous pouvons interroger le livre que nous venons de créer dans MongoDB :

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

assertEquals(1, books.size());

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

L'interrogation d'un document dans Morphia commence par la création d'une requête à l'aide de Datastore puis en ajoutant des filtres de manière déclarative, pour le plus grand plaisir des amoureux de la programmation fonctionnelle !

Morphia prend en charge la construction de requêtes beaucoup plus complexes avec des filtres et des opérateurs. De plus, Morphia permet de limiter, de sauter et de classer les résultats dans la requête.

De plus, Morphia nous permet d'utiliser des requêtes brutes écrites avec le pilote Java pour MongoDB pour plus de contrôle, si nécessaire.

6.3. Mettre à jour

Bien qu'une opération de sauvegarde puisse gérer les mises à jour si la clé primaire correspond, Morphia fournit des moyens de mettre à jour les documents de manière sélective :

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

Ici, nous construisons une requête et une opération de mise à jour pour augmenter de un le prix de tous les livres renvoyés par la requête.

6.4. Supprimer

Enfin, ce qui a été créé doit être supprimé ! Encore une fois, avec Morphia, c'est assez intuitif :

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

Nous créons la requête de la même manière qu'auparavant et exécutons l'opération de suppression sur le Datastore .

7. Utilisation avancée

MongoDB a certaines opérations avancées comme l'agrégation, l'indexation et bien d'autres . Bien qu'il ne soit pas possible d'effectuer tout cela en utilisant Morphia, il est certainement possible d'en réaliser une partie. Pour les autres, malheureusement, nous devrons nous rabattre sur le pilote Java pour MongoDB.

Concentrons-nous sur certaines de ces opérations avancées que nous pouvons effectuer via Morphia.

7.1. Agrégation

L'agrégation dans MongoDB nous permet de définir une série d'opérations dans un pipeline pouvant fonctionner sur un ensemble de documents et produire une sortie agrégée .

Morphia dispose d'une API pour prendre en charge un tel pipeline d'agrégation.

Supposons que nous souhaitions agréger les données de notre bibliothèque de telle manière que nous ayons tous les livres regroupés par leur auteur :

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

Donc comment ça fonctionne? Nous commençons par créer un pipeline d'agrégation en utilisant le même ancien Datastore . Nous devons fournir l'entité sur laquelle nous souhaitons effectuer des opérations d'agrégation, par exemple, Book ici.

Ensuite, nous voulons regrouper les documents par "auteur" et agréger leur "titre" sous une clé appelée "livres". Enfin, nous travaillons ici avec un ODM. Donc, nous devons définir une entité pour collecter nos données agrégées — dans notre cas, c'est Auteur .

Bien sûr, nous devons définir une entité appelée Auteur avec une variable appelée livres :

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

Ceci, bien sûr, ne fait qu'effleurer la surface d'une construction très puissante fournie par MongoDB et peut être exploré plus en détail pour plus de détails.

7.2. Projection

La projection dans MongoDB nous permet de sélectionner uniquement les champs que nous voulons récupérer à partir des documents dans nos requêtes . Dans le cas où la structure du document est complexe et lourde, cela peut être très utile lorsque nous n'avons besoin que de quelques champs.

Supposons que nous ayons seulement besoin de récupérer les livres avec leur titre dans notre requête :

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

Ici, comme nous pouvons le voir, nous ne récupérons que le titre dans notre résultat et non l'auteur et les autres champs. Nous devons cependant être prudents dans l'utilisation de la sortie projetée lors de l'enregistrement dans MongoDB. Cela peut entraîner une perte de données !

7.3. Indexation

Les index jouent un rôle très important dans l'optimisation des requêtes avec les bases de données, qu'elles soient relationnelles ou non relationnelles.

MongoDB définit les index au niveau de la collection avec un index unique créé sur la clé primaire par défaut . De plus, MongoDB permet de créer des index sur n'importe quel champ ou sous-champ d'un document. Nous devons choisir de créer un index sur une clé en fonction de la requête que nous souhaitons créer.

Par exemple, dans notre exemple, nous pouvons souhaiter créer un index sur le champ "titre" de Livre car nous finissons souvent par l'interroger :

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

Bien sûr, nous pouvons passer des options d'indexation supplémentaires pour adapter les nuances de l'index qui est créé. Notez que le champ doit être annoté par @Propriété à utiliser dans un index.

De plus, en plus de l'index au niveau de la classe, Morphia a une annotation pour définir également un index au niveau du champ.

7.4. Validation du schéma

Nous avons la possibilité de fournir des règles de validation des données pour une collection que MongoDB peut utiliser lors d'une opération de mise à jour ou d'insertion . Morphia prend en charge cela via ses API.

Disons que nous ne voulons pas insérer un livre sans prix valide. Nous pouvons tirer parti de la validation de schéma pour y parvenir :

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

Il existe un riche ensemble de validations fournies par MongoDB qui peuvent être utilisées ici.

8. ODM MongoDB alternatifs

Morphia n'est pas le seul ODM MongoDB disponible pour Java. Il y en a plusieurs autres que nous pouvons envisager d'utiliser dans nos applications. Une discussion sur la comparaison avec Morphia n'est pas possible ici, mais il est toujours utile de connaître nos options :

  • Spring Data :fournit un modèle de programmation basé sur Spring pour travailler avec MongoDB
  • MongoJack :Fournit un mappage direct des objets JSON aux objets MongoDB

Il ne s'agit pas d'une liste complète des ODM MongoDB pour Java, mais il existe des alternatives intéressantes disponibles !


No