Uma implementação de marcação simples com o MongoDB
1. Visão geral
Neste tutorial, daremos uma olhada em uma implementação de marcação simples usando Java e MongoDB.
Para quem não está familiarizado com o conceito,a tag is a keyword used as a “label” to group documents into different categories. Isso permite que os usuários naveguem rapidamente por conteúdo semelhante e é especialmente útil ao lidar com uma grande quantidade de dados.
Dito isso, não é surpreendente que essa técnica seja muito comumente usada em blogs. Nesse cenário, cada postagem possui uma ou mais tags de acordo com os tópicos abordados. Quando o usuário termina de ler, ele pode seguir uma das tags para visualizar mais conteúdo relacionado a esse tópico.
Vamos ver como podemos implementar este cenário.
2. Dependência
Para consultar o banco de dados, teremos que incluir a dependência do driver MongoDB em nossopom.xml:
org.mongodb
mongo-java-driver
3.6.3
A versão atual desta dependência pode ser encontradahere.
3. Modelo de dados
Em primeiro lugar, vamos começar planejando a aparência de um documento de postagem.
Para simplificar, nosso modelo de dados terá apenas um título, que também usaremos como o id do documento, um autor e algumas tags.
Iremos armazenar as tags dentro de uma matriz, pois uma postagem provavelmente terá mais de uma:
{
"_id" : "Java 8 and MongoDB",
"author" : "Donato Rimenti",
"tags" : ["Java", "MongoDB", "Java 8", "Stream API"]
}
Também criaremos a classe de modelo Java correspondente:
public class Post {
private String title;
private String author;
private List tags;
// getters and setters
}
4. Atualizando tags
Agora que configuramos o banco de dados e inserimos alguns posts de amostra, vamos ver como podemos atualizá-los.
Our repository class will include two methods to handle the addition and removal of tags usando o título para encontrá-los. Também retornaremos um booleano para indicar se a consulta atualizou um elemento ou não:
public boolean addTags(String title, List 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 tags) {
UpdateResult result = collection.updateOne(
new BasicDBObject(DBCollection.ID_FIELD_NAME, title),
Updates.pullAll(TAGS_FIELD, tags));
return result.getModifiedCount() == 1;
}
Usamos o métodoaddEachToSet em vez depush para a adição, de modo que, se as tags já estiverem lá, não as adicionemos novamente.
Observe também que o operadoraddToSet também não funcionaria, pois adicionaria as novas tags como uma matriz aninhada que não é o que queremos.
Another way we can perform our updates is through the Mongo shell. Por exemplo, vamos atualizar o postJUnit5 with Java. Em particular, queremos adicionar as tagsJavae JUnit5 e remover as tagsSpringeREST:
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. Consultas
Por último, mas não menos importante, vamos examinar algumas das consultas mais comuns nas quais podemos estar interessados ao trabalhar com tags. Para este propósito, tiraremos vantagem de três operadores de array em particular:
-
$in – retorna os documentos ondea field contains any value da matriz especificada
-
$nin – retorna os documentos ondea field doesn’t contain any value da matriz especificada
-
$all – retorna os documentos ondea field contains all the values da matriz especificada
We’ll define three methods to query the posts in relation to a collection of tags passed as arguments. Eles retornarão as postagens que correspondem a pelo menos uma tag, todas as tags e nenhuma delas. Também criaremos um método de mapeamento para lidar com a conversão entre um documento e nosso modelo usando a API Stream do Java 8:
public List postsWithAtLeastOneTag(String... tags) {
FindIterable results = collection
.find(Filters.in(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List postsWithAllTags(String... tags) {
FindIterable results = collection
.find(Filters.all(TAGS_FIELD, tags));
return StreamSupport.stream(results.spliterator(), false)
.map(TagRepository::documentToPost)
.collect(Collectors.toList());
}
public List postsWithoutTags(String... tags) {
FindIterable 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) document.get(TAGS_FIELD));
return post;
}
Novamente,let’s also take a look at the shell equivalent queries. Iremos buscar três pós-coleções diferentes, respectivamente marcadas comMongoDB ouStream API, marcadas comJava 8eJUnit 5e não marcadas comGroovy nemScala:
db.posts.find({
"tags" : { $in : ["MongoDB", "Stream API" ] }
});
db.posts.find({
"tags" : { $all : ["Java 8", "JUnit 5" ] }
});
db.posts.find({
"tags" : { $nin : ["Groovy", "Scala" ] }
});
6. Conclusão
Neste artigo, mostramos como criar um mecanismo de marcação. Obviamente, podemos usar e readaptar essa mesma metodologia para outros fins, além de um blog.
Se você estiver interessado em aprender mais sobre MongoDB,we encourage you to read this introductory article.
Como sempre, todo o código do exemplo está disponívelover on the Github project.