MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Una semplice implementazione di tagging con MongoDB

Questo articolo fa parte di una serie:• Un'implementazione semplice di tagging con Elasticsearch
• Una semplice implementazione di tagging con JPA
• Un'implementazione di tagging avanzata con JPA
• Una semplice implementazione di tagging con MongoDB (articolo corrente)

1. Panoramica

In questo tutorial, daremo un'occhiata a una semplice implementazione di tagging utilizzando Java e MongoDB.

Per chi non conosce il concetto, un tag è una parola chiave utilizzata come "etichetta" per raggruppare i documenti in diverse categorie. Ciò consente agli utenti di navigare rapidamente attraverso contenuti simili ed è particolarmente utile quando si tratta di una grande quantità di dati.

Detto questo, non sorprende che questa tecnica sia molto comunemente usata nei blog. In questo scenario, ogni post ha uno o più tag in base agli argomenti trattati. Al termine della lettura, l'utente può seguire uno dei tag per visualizzare più contenuti relativi a quell'argomento.

Vediamo come possiamo implementare questo scenario.

2. Dipendenza

Per interrogare il database, dovremo includere la dipendenza del driver MongoDB nel nostro pom.xml :

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongo-java-driver</artifactId>
    <version>3.6.3</version>
</dependency>

La versione corrente di questa dipendenza può essere trovata qui.

3. Modello di dati

Prima di tutto, iniziamo pianificando come dovrebbe essere un documento di post.

Per semplificare, il nostro modello di dati avrà solo un titolo, che useremo anche come ID del documento, un autore e alcuni tag.

Memorizziamo i tag all'interno di un array poiché un post probabilmente ne avrà più di uno:

{
    "_id" : "Java 8 and MongoDB",
    "author" : "Donato Rimenti",
    "tags" : ["Java", "MongoDB", "Java 8", "Stream API"]
}

Creeremo anche la classe del modello Java corrispondente:

public class Post {
    private String title;
    private String author;
    private List<String> tags;

    // getters and setters
}

4. Aggiornamento dei tag

Ora che abbiamo impostato il database e inserito un paio di post di esempio, vediamo come aggiornarli.

La nostra classe di repository includerà due metodi per gestire l'aggiunta e la rimozione dei tag usando il titolo per trovarli. Restituiremo anche un valore booleano per indicare se la query ha aggiornato un elemento o meno:

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

Abbiamo usato addEachToSet metodo invece di push per l'aggiunta in modo che se i tag sono già presenti, non li aggiungeremo di nuovo.

Si noti inoltre che addToSet anche l'operatore non funzionerebbe poiché aggiungerebbe i nuovi tag come un array nidificato che non è quello che vogliamo.

Un altro modo in cui possiamo eseguire i nostri aggiornamenti è tramite la shell Mongo. Ad esempio, aggiorniamo il post JUnit5 con Java. In particolare, vogliamo aggiungere i tag Java e JUnità 5 e rimuovi i tag Primavera e RIPOSO :

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. Query

Ultimo ma non meno importante, esaminiamo alcune delle query più comuni che potrebbero interessarci mentre lavoriamo con i tag. A tale scopo, sfrutteremo in particolare tre operatori di array:

  • $in – restituisce i documenti in cui un campo contiene qualsiasi valore dell'array specificato
  • $ nove – restituisce i documenti in cui un campo non contiene alcun valore dell'array specificato
  • $tutti – restituisce i documenti in cui un campo contiene tutti i valori dell'array specificato

Definiremo tre metodi per interrogare i post in relazione a una raccolta di tag passati come argomenti . Restituiranno i post che corrispondono ad almeno un tag, tutti i tag e nessuno dei tag. Creeremo anche un metodo di mappatura per gestire la conversione tra un documento e il nostro modello utilizzando l'API Stream di 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;
}

Ancora una volta, diamo anche un'occhiata alle query equivalenti alla shell . Recupereremo tre diverse raccolte di post contrassegnate rispettivamente con MongoDB o Stream API, contrassegnate da entrambi Java 8 e Junit 5 e non contrassegnati con GroovyScala :

db.posts.find({
    "tags" : { $in : ["MongoDB", "Stream API" ] } 
});

db.posts.find({
    "tags" : { $all : ["Java 8", "JUnit 5" ] } 
});

db.posts.find({
    "tags" : { $nin : ["Groovy", "Scala" ] } 
});