Cet article fait partie d'une série :• Une implémentation simple du balisage avec Elasticsearch
• Une implémentation de balisage simple avec JPA
• Une implémentation de balisage avancé avec JPA
• Une implémentation simple du balisage avec MongoDB (article actuel)
1. Présentation
Dans ce didacticiel, nous allons examiner une implémentation de balisage simple à l'aide de Java et de MongoDB.
Pour ceux qui ne connaissent pas le concept, une balise est un mot clé utilisé comme "étiquette" pour regrouper les documents en différentes catégories. Cela permet aux utilisateurs de naviguer rapidement dans un contenu similaire et c'est particulièrement utile lorsqu'il s'agit de traiter une grande quantité de données.
Cela étant dit, il n'est pas surprenant que cette technique soit très couramment utilisée dans les blogs. Dans ce scénario, chaque article comporte un ou plusieurs tags selon les sujets abordés. Lorsque l'utilisateur a fini de lire, il peut suivre l'une des balises pour afficher plus de contenu lié à ce sujet.
Voyons comment nous pouvons implémenter ce scénario.
2. Dépendance
Afin d'interroger la base de données, nous devrons inclure la dépendance du pilote MongoDB dans notre pom.xml :
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.6.3</version>
</dependency>
La version actuelle de cette dépendance peut être trouvée ici.
3. Modèle de données
Tout d'abord, commençons par planifier à quoi devrait ressembler un document de publication.
Pour rester simple, notre modèle de données n'aura qu'un titre, que nous utiliserons également comme identifiant de document, un auteur et quelques balises.
Nous stockerons les balises dans un tableau puisqu'une publication en aura probablement plus d'une :
{
"_id" : "Java 8 and MongoDB",
"author" : "Donato Rimenti",
"tags" : ["Java", "MongoDB", "Java 8", "Stream API"]
}
Nous allons également créer la classe de modèle Java correspondante :
public class Post {
private String title;
private String author;
private List<String> tags;
// getters and setters
}
4. Mise à jour des balises
Maintenant que nous avons configuré la base de données et inséré quelques exemples d'articles, voyons comment nous pouvons les mettre à jour.
Notre classe de référentiel comprendra deux méthodes pour gérer l'ajout et la suppression de balises en utilisant le titre pour les trouver. Nous renverrons également un booléen pour indiquer si la requête a mis à jour un élément ou non :
public boolean addTags(String title, List<String> tags) {
UpdateResult result = collection.updateOne(
new BasicDBObject(DBCollection.ID_FIELD_NAME, title),
Updates.addEachToSet(TAGS_FIELD, tags));
return result.getModifiedCount() == 1;
}
public boolean removeTags(String title, List<String> tags) {
UpdateResult result = collection.updateOne(
new BasicDBObject(DBCollection.ID_FIELD_NAME, title),
Updates.pullAll(TAGS_FIELD, tags));
return result.getModifiedCount() == 1;
}
Nous avons utilisé le addEachToSet méthode au lieu de push pour l'ajout afin que si les balises sont déjà là, nous ne les ajouterons plus.
Notez également que le addToSet ne fonctionnerait pas non plus car il ajouterait les nouvelles balises sous forme de tableau imbriqué, ce qui n'est pas ce que nous voulons.
Une autre façon d'effectuer nos mises à jour consiste à utiliser le shell Mongo. Par exemple, mettons à jour le post JUnit5 avec Java. En particulier, nous voulons ajouter les balises Java et JUnité5 et supprimer les balises Printemps et REPOS :
db.posts.updateOne(
{ _id : "JUnit 5 with Java" },
{ $addToSet :
{ "tags" :
{ $each : ["Java", "JUnit5"] }
}
});
db.posts.updateOne(
{_id : "JUnit 5 with Java" },
{ $pull :
{ "tags" : { $in : ["Spring", "REST"] }
}
});
5. Requêtes
Enfin, passons en revue certaines des requêtes les plus courantes qui pourraient nous intéresser lorsque nous travaillons avec des balises. Pour cela, nous profiterons en particulier de trois opérateurs de tableau :
- en $ – renvoie les documents où un champ contient n'importe quelle valeur du tableau spécifié
- neuf $ – renvoie les documents où un champ ne contient aucune valeur du tableau spécifié
- $tout – renvoie les documents où un champ contient toutes les valeurs du tableau spécifié
Nous allons définir trois méthodes pour interroger les publications par rapport à une collection de balises passées en arguments . Ils renverront les publications qui correspondent à au moins une balise, toutes les balises et aucune des balises. Nous allons également créer une méthode de mappage pour gérer la conversion entre un document et notre modèle à l'aide de l'API Stream de Java 8 :
public List<Post> postsWithAtLeastOneTag(String... tags) {
FindIterable<Document> results = collection
.find(Filters.in(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List<Post> postsWithAllTags(String... tags) {
FindIterable<Document> results = collection
.find(Filters.all(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List<Post> postsWithoutTags(String... tags) {
FindIterable<Document> results = collection
.find(Filters.nin(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
private static Post documentToPost(Document document) {
Post post = new Post();
post.setTitle(document.getString(DBCollection.ID_FIELD_NAME));
post.setAuthor(document.getString("author"));
post.setTags((List<String>) document.get(TAGS_FIELD));
return post;
}
Encore une fois, jetons également un coup d'œil aux requêtes équivalentes au shell . Nous allons chercher trois collections de publications différentes étiquetées respectivement avec MongoDB ou Diffusion API, balisée avec Java 8 et JUnit 5 et non tagué avec Groovy ni Scala :
db.posts.find({
"tags" : { $in : ["MongoDB", "Stream API" ] }
});
db.posts.find({
"tags" : { $all : ["Java 8", "JUnit 5" ] }
});
db.posts.find({
"tags" : { $nin : ["Groovy", "Scala" ] }
});