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.