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

Introduzione a Spring Data MongoDB

1. Panoramica

Questo articolo sarà una rapida e pratica introduzione a Spring Data MongoDB.

Esamineremo le nozioni di base utilizzando sia il MongoTemplate così come MongoRepository , con esempi pratici per illustrare ogni operazione.


Ulteriori letture:

Supporto geospaziale in MongoDB

Dai un'occhiata a come archiviare, indicizzare e cercare dati geospaziali con MongoDBLeggi di più →

Test di integrazione Spring Boot con MongoDB integrato

Scopri come utilizzare la soluzione MongoDB incorporata di Flapdoodle insieme a Spring Boot per eseguire senza problemi i test di integrazione di MongoDB.Leggi di più →

2. Modello Mongo e MongoRepository

Il Modello Mongo segue il modello di modello standard in primavera e fornisce un'API di base pronta per l'uso al motore di persistenza sottostante.

Il deposito segue l'approccio Spring Data-centric e include operazioni API più flessibili e complesse, basate sui modelli di accesso ben noti in tutti i progetti Spring Data.

Per entrambi, dobbiamo iniziare definendo la dipendenza, ad esempio in pom.xml , con Maven:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>

Per verificare se è stata rilasciata una nuova versione della libreria, monitora le versioni qui.

3. Configurazione per MongoTemplate

3.1. Configurazione XML

Iniziamo con la semplice configurazione XML per il modello Mongo:

<mongo:mongo-client id="mongoClient" host="localhost" />
<mongo:db-factory id="mongoDbFactory" dbname="test" mongo-client-ref="mongoClient" />

Per prima cosa dobbiamo definire il bean factory responsabile della creazione di istanze Mongo.

Successivamente, dobbiamo effettivamente definire (e configurare) il bean modello:

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 
    <constructor-arg ref="mongoDbFactory"/> 
</bean>

Infine, dobbiamo definire un post processor per tradurre qualsiasi MongoExceptions lanciato in @Repository classi annotate:

<bean class=
  "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

3.2. Configurazione Java

Creiamo ora una configurazione simile usando la configurazione Java estendendo la classe base per la configurazione di MongoDB AbstractMongoConfiguration :

@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
 
    @Override
    protected String getDatabaseName() {
        return "test";
    }
 
    @Override
    public MongoClient mongoClient() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
            .applyConnectionString(connectionString)
            .build();
        
        return MongoClients.create(mongoClientSettings);
    }
 
    @Override
    public Collection getMappingBasePackages() {
        return Collections.singleton("com.baeldung");
    }
}

Tieni presente che non era necessario definire MongoTemplate bean nella configurazione precedente poiché è già definito in AbstractMongoClientConfiguration .

Possiamo anche utilizzare la nostra configurazione da zero senza estendere AbstractMongoClientConfiguration :

@Configuration
public class SimpleMongoConfig {
 
    @Bean
    public MongoClient mongo() {
        ConnectionString connectionString = new ConnectionString("mongodb://localhost:27017/test");
        MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
          .applyConnectionString(connectionString)
          .build();
        
        return MongoClients.create(mongoClientSettings);
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongo(), "test");
    }
}

4. Configurazione per MongoRepository

4.1. Configurazione XML

Per utilizzare repository personalizzati (estendendo il MongoRepository ), è necessario continuare la configurazione dalla sezione 3.1. e imposta i repository:

<mongo:repositories 
  base-package="com.baeldung.repository" mongo-template-ref="mongoTemplate"/>

4.2. Configurazione Java

Allo stesso modo, costruiremo sulla configurazione che abbiamo già creato nella sezione 3.2. e aggiungi una nuova annotazione nel mix:

@EnableMongoRepositories(basePackages = "com.baeldung.repository")

4.3. Crea il repository

Dopo la configurazione, dobbiamo creare un repository, estendendo il MongoRepository esistente interfaccia:

public interface UserRepository extends MongoRepository<User, String> {
    // 
}

Ora possiamo cablare automaticamente questo UserRepository e usa le operazioni da MongoRepository o aggiungi operazioni personalizzate.

5. Utilizzando MongoTemplate

5.1. Inserisci

Iniziamo con l'operazione di inserimento e con un database vuoto:

{
}

Ora se inseriamo un nuovo utente:

User user = new User();
user.setName("Jon");
mongoTemplate.insert(user, "user");

il database sarà simile a questo:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

5.2. Salva – Inserisci

Il salva l'operazione ha una semantica di salvataggio o aggiornamento:se è presente un id, esegue un aggiornamento e, in caso contrario, esegue un inserimento.

Diamo un'occhiata alla prima semantica:l'inserto.

Ecco lo stato iniziale del database:

{
}

Quando ora salviamo un nuovo utente:

User user = new User();
user.setName("Albert"); 
mongoTemplate.save(user, "user");

l'entità verrà inserita nel database:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Albert"
}

Successivamente, esamineremo la stessa operazione:salva — con semantica di aggiornamento.

5.3. Salva – Aggiorna

Diamo ora un'occhiata a salva con semantica di aggiornamento, operando su un'entità esistente:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"
}

Quando salviamo l'utente esistente, lo aggiorneremo:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
mongoTemplate.save(user, "user");

Il database sarà simile a questo:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Possiamo vedere che in questo particolare esempio, salva utilizza la semantica di aggiornamento perché usiamo un oggetto con _id dato .

5.4. UpdateFirst

updateFirst aggiorna il primo documento che corrisponde alla query.

Iniziamo con lo stato iniziale del database:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

Quando ora eseguiamo updateFirst :

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Alex"));
Update update = new Update();
update.set("name", "James");
mongoTemplate.updateFirst(query, update, User.class);

solo la prima voce verrà aggiornata:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "James"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Alex"
    }
]

5.5. Aggiorna Multi

Aggiorna Multi aggiorna tutti i documenti che corrispondono alla query specificata.

Innanzitutto, ecco lo stato del database prima di eseguire updateMulti :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Eugen"
    }
]

Ora eseguiamo updateMulti operazione:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eugen"));
Update update = new Update();
update.set("name", "Victor");
mongoTemplate.updateMulti(query, update, User.class);

Entrambi gli oggetti esistenti verranno aggiornati nel database:

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614c"),
        "_class" : "com.baeldung.model.User",
        "name" : "Victor"
    }
]

5.6. Trova e modifica

Questa operazione funziona come updateMulti , ma restituisce l'oggetto prima che fosse modificato.

Innanzitutto, questo è lo stato del database prima di chiamare findAndModify :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Diamo un'occhiata al codice operativo effettivo:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
User user = mongoTemplate.findAndModify(query, update, User.class);

L'oggetto utente restituito ha gli stessi valori dello stato iniziale nel database.

Tuttavia, questo è il nuovo stato nel database:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.7. Inserimento

Il sottosopra funziona su trova e modifica altro crea semantica :se il documento è abbinato, aggiornalo, oppure crea un nuovo documento combinando l'oggetto query e update.

Iniziamo con lo stato iniziale del database:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Markus"
}

Ora eseguiamo l'upsert :

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Markus"));
Update update = new Update();
update.set("name", "Nick");
mongoTemplate.upsert(query, update, User.class);

Ecco lo stato del database dopo l'operazione:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Nick"
}

5.8. Rimuovi

Esamineremo lo stato del database prima di chiamare remove :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Ora eseguiamo remove :

mongoTemplate.remove(user, "user");

Il risultato sarà come previsto:

{
}

6. Utilizzando MongoRepository

6.1. Inserisci

Per prima cosa, vedremo lo stato del database prima di eseguire l'insert :

{
}

Ora inseriamo un nuovo utente:

User user = new User();
user.setName("Jon");
userRepository.insert(user);

Ed ecco lo stato finale del database:

{
    "_id" : ObjectId("55b4fda5830b550a8c2ca25a"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jon"
}

Nota come l'operazione funziona allo stesso modo dell'inserto nel Modello Mongo API.

6.2. Salva – Inserisci

Allo stesso modo, salva funziona come il salvataggio operazione nelMongoTemplate API.

Iniziamo osservando la semantica di inserimento dell'operazione.

Ecco lo stato iniziale del database:

{
}

Ora eseguiamo il salvataggio operazione:

User user = new User();
user.setName("Aaron");
userRepository.save(user);

Ciò comporta l'aggiunta dell'utente al database:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Aaron"
}

Nota ancora come salvare funziona con inserire semantica perché stiamo inserendo un nuovo oggetto.

6.3. Salva – Aggiorna

Esaminiamo ora la stessa operazione ma con aggiornamento semantica.

Innanzitutto, ecco lo stato del database prima di eseguire il nuovo salvataggio :

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jack"81*6
}

Ora eseguiamo l'operazione:

user = mongoTemplate.findOne(
  Query.query(Criteria.where("name").is("Jack")), User.class);
user.setName("Jim");
userRepository.save(user);

Infine, ecco lo stato del database:

{
    "_id" : ObjectId("55b52bb7830b8c9b544b6ad5"),
    "_class" : "com.baeldung.model.User",
    "name" : "Jim"
}

Nota ancora come salvare funziona con aggiornamento semantica perché stiamo usando un oggetto esistente.

6.4. Elimina

Ecco lo stato del database prima di chiamare delete :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Benn"
}

Eseguiamo elimina :

userRepository.delete(user);

Ed ecco il nostro risultato:

{
}

6.5. Trova uno

Successivamente, questo è lo stato del database quando findOne si chiama:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

Ora eseguiamo findOne :

userRepository.findOne(user.getId())

E il risultato restituirà i dati esistenti:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Chris"
}

6.6. Esiste

Lo stato del database prima della chiamata esiste :

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Harris"
}

Ora eseguiamo exists , che ovviamente restituirà true :

boolean isExists = userRepository.exists(user.getId());

6.7. Trova tutto Con Ordina

Lo stato del database prima di chiamare findAll :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Ora eseguiamo findAll con Ordina :

List<User> users = userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));

Il risultato sarà ordinato per nome in ordine crescente :

[
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    },
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    }
]

6.8. Trova tutto Con Paginabile

Lo stato del database prima di chiamare findAll :

[
    {
        "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Brendan"
    },
    {
        "_id" : ObjectId("67b5ffa5511fee0e45ed614b"),
        "_class" : "com.baeldung.model.User",
        "name" : "Adam"
    }
]

Ora eseguiamo findAll con una richiesta di impaginazione:

Pageable pageableRequest = PageRequest.of(0, 1);
Page<User> page = userRepository.findAll(pageableRequest);
List<User> users = pages.getContent();

Gli utenti risultanti list sarà un solo utente:

{
    "_id" : ObjectId("55b5ffa5511fee0e45ed614b"),
    "_class" : "com.baeldung.model.User",
    "name" : "Brendan"
}

7. Annotazioni

Infine, esaminiamo anche le semplici annotazioni che Spring Data utilizza per guidare queste operazioni API.

Il livello di campo @Id l'annotazione può decorare qualsiasi tipo, incluso lungo e stringa :

@Id
private String id;

Se il valore di @Id il campo non è nullo, è archiviato nel database così com'è; in caso contrario, il convertitore presumerà di voler memorizzare un ObjectId nel database (o ObjectId , Stringa oppure Intero grande lavoro).

Di seguito esamineremo @Document :

@Document
public class User {
    //
}

Questa annotazione semplicemente contrassegna una classe come oggetto di dominio che deve essere mantenuto nel database, oltre a permetterci di scegliere il nome della raccolta da utilizzare.