Dieser Artikel ist Teil einer Reihe:• Eine einfache Tagging-Implementierung mit Elasticsearch
• Eine einfache Tagging-Implementierung mit JPA
• Eine erweiterte Tagging-Implementierung mit JPA
• Eine einfache Tagging-Implementierung mit MongoDB (aktueller Artikel)
1. Übersicht
In diesem Tutorial werfen wir einen Blick auf eine einfache Tagging-Implementierung mit Java und MongoDB.
Für diejenigen, die mit dem Konzept nicht vertraut sind, ein Tag ist ein Schlüsselwort, das als „Label“ verwendet wird, um Dokumente in verschiedene Kategorien zu gruppieren. Dies ermöglicht den Benutzern, schnell durch ähnliche Inhalte zu navigieren, und ist besonders nützlich, wenn mit einer großen Datenmenge umgegangen wird.
Davon abgesehen ist es nicht verwunderlich, dass diese Technik in Blogs sehr häufig verwendet wird. In diesem Szenario hat jeder Beitrag ein oder mehrere Tags entsprechend den behandelten Themen. Wenn der Benutzer mit dem Lesen fertig ist, kann er einem der Tags folgen, um weitere Inhalte zu diesem Thema anzuzeigen.
Mal sehen, wie wir dieses Szenario implementieren können.
2. Abhängigkeit
Um die Datenbank abzufragen, müssen wir die MongoDB-Treiberabhängigkeit in unsere pom.xml aufnehmen :
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.6.3</version>
</dependency>
Die aktuelle Version dieser Abhängigkeit finden Sie hier.
3. Datenmodell
Beginnen wir zunächst mit der Planung, wie ein Beitragsdokument aussehen soll.
Um es einfach zu halten, hat unser Datenmodell nur einen Titel, den wir auch als Dokument-ID verwenden, einen Autor und einige Tags.
Wir speichern die Tags in einem Array, da ein Post wahrscheinlich mehr als nur einen hat:
{
"_id" : "Java 8 and MongoDB",
"author" : "Donato Rimenti",
"tags" : ["Java", "MongoDB", "Java 8", "Stream API"]
}
Wir erstellen auch die entsprechende Java-Modellklasse:
public class Post {
private String title;
private String author;
private List<String> tags;
// getters and setters
}
4. Tags aktualisieren
Nachdem wir nun die Datenbank eingerichtet und einige Beispielbeiträge eingefügt haben, sehen wir uns an, wie wir sie aktualisieren können.
Unsere Repository-Klasse wird zwei Methoden enthalten, um das Hinzufügen und Entfernen von Tags zu handhaben indem Sie den Titel verwenden, um sie zu finden. Wir geben auch einen booleschen Wert zurück, um anzugeben, ob die Abfrage ein Element aktualisiert hat oder nicht:
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;
}
Wir haben addEachToSet verwendet -Methode anstelle von push für die Hinzufügung, sodass wir sie nicht noch einmal hinzufügen, wenn die Tags bereits vorhanden sind.
Beachten Sie auch, dass das addToSet Operator würde auch nicht funktionieren, da er die neuen Tags als verschachteltes Array hinzufügen würde, was nicht das ist, was wir wollen.
Eine andere Möglichkeit, wie wir unsere Aktualisierungen durchführen können, ist die Mongo-Shell. Lassen Sie uns zum Beispiel den Beitrag JUnit5 mit Java. aktualisieren Insbesondere wollen wir die Tags Java hinzufügen und JUnit5 und entfernen Sie die Tags Frühling und REST :
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. Abfragen
Lassen Sie uns zu guter Letzt einige der häufigsten Abfragen durchgehen, die uns bei der Arbeit mit Tags interessieren könnten. Zu diesem Zweck nutzen wir insbesondere drei Array-Operatoren:
- $in – gibt die Dokumente zurück, in denen ein Feld einen beliebigen Wert enthält des angegebenen Arrays
- $nin – gibt die Dokumente zurück, in denen ein Feld keinen Wert enthält des angegebenen Arrays
- $all – gibt die Dokumente zurück, in denen ein Feld alle Werte enthält des angegebenen Arrays
Wir werden drei Methoden definieren, um die Posts in Bezug auf eine Sammlung von Tags abzufragen, die als Argumente übergeben werden . Sie geben die Beiträge zurück, die mindestens einem Tag, allen Tags und keinem der Tags entsprechen. Wir werden auch eine Zuordnungsmethode erstellen, um die Konvertierung zwischen einem Dokument und unserem Modell mithilfe der Stream-API von Java 8 zu handhaben:
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;
}
Auch hier werfen wir einen Blick auf die Shell-äquivalenten Abfragen . Wir werden drei verschiedene Post-Collections abrufen, die jeweils mit MongoDB getaggt sind oder Streamen API, getaggt sowohl mit Java 8 und JUnit 5 und nicht mit Groovy getaggt noch 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" ] }
});