MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Introduction à Spring Data MongoDB

1. Présentation

Cet article sera une introduction rapide et pratique à Spring Data MongoDB.

Nous allons passer en revue les bases en utilisant à la fois le MongoTemplate ainsi que MongoRepository , avec des exemples pratiques pour illustrer chaque opération.


Pour en savoir plus :

Support géospatial dans MongoDB

Découvrez comment stocker, indexer et rechercher des données géospatiales avec MongoDBEn savoir plus →

Test d'intégration Spring Boot avec MongoDB intégré

Apprenez à utiliser la solution MongoDB intégrée de Flapdoodle avec Spring Boot pour exécuter les tests d'intégration MongoDB en douceur.En savoir plus →

2. Modèle Mongo et MongoRepository

Le Modèle Mongo suit le modèle de modèle standard de Spring et fournit une API de base prête à l'emploi au moteur de persistance sous-jacent.

Le référentiel suit l'approche centrée sur Spring Data et propose des opérations d'API plus flexibles et complexes, basées sur les modèles d'accès bien connus dans tous les projets Spring Data.

Pour les deux, nous devons commencer par définir la dépendance — par exemple, dans le pom.xml , avec Maven :

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

Pour vérifier si une nouvelle version de la bibliothèque a été publiée, suivez les versions ici.

3. Configuration pour MongoTemplate

3.1. Configuration XML

Commençons par la configuration XML simple du modèle Mongo :

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

Nous devons d'abord définir le bean d'usine responsable de la création des instances Mongo.

Ensuite, nous devons réellement définir (et configurer) le bean modèle :

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

Et enfin, nous devons définir un post-processeur pour traduire toutes les MongoExceptions jeté dans @Repository classes annotées :

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

3.2. Paramétrage Java

Créons maintenant une configuration similaire à l'aide de la configuration Java en étendant la classe de base pour la configuration 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");
    }
}

Notez que nous n'avons pas eu besoin de définir MongoTemplate bean dans la configuration précédente puisqu'il est déjà défini dans AbstractMongoClientConfiguration .

Nous pouvons également utiliser notre configuration à partir de zéro sans étendre 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. Configuration pour MongoRepository

4.1. Configuration XML

Pour utiliser des référentiels personnalisés (en étendant le MongoRepository ), nous devons continuer la configuration à partir de la section 3.1. et configurez les référentiels :

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

4.2. Paramétrage Java

De même, nous allons construire sur la configuration que nous avons déjà créée dans la section 3.2. et ajoutez une nouvelle annotation au mix :

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

4.3. Créer le référentiel

Après la configuration, nous devons créer un référentiel — en étendant le MongoRepository existant interface :

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

Maintenant, nous pouvons connecter automatiquement ce UserRepository et utiliser les opérations de MongoRepository ou ajouter des opérations personnalisées.

5. Utiliser MongoTemplate

5.1. Insérer

Commençons par l'opération d'insertion ainsi qu'une base de données vide :

{
}

Maintenant, si nous insérons un nouvel utilisateur :

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

la base de données ressemblera à ceci :

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

5.2. Enregistrer – Insérer

La sauvegarde l'opération a une sémantique de sauvegarde ou de mise à jour :si un identifiant est présent, elle effectue une mise à jour, et sinon, elle effectue une insertion.

Regardons la première sémantique - l'insertion.

Voici l'état initial de la base de données :

{
}

Quand maintenant nous sauvons un nouvel utilisateur :

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

l'entité sera insérée dans la base de données :

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

Ensuite, nous examinerons la même opération :enregistrer — avec sémantique de mise à jour.

5.3. Enregistrer – Mettre à jour

Regardons maintenant enregistrer avec sémantique de mise à jour, opérant sur une entité existante :

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

Quand nous économisons l'utilisateur existant, nous le mettrons à jour :

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

La base de données ressemblera à ceci :

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

Nous pouvons voir que dans cet exemple particulier, save utilise la sémantique de update parce que nous utilisons un objet avec _id donné .

5.4. Mettre à jour d'abord

mettre à jour d'abord met à jour le tout premier document qui correspond à la requête.

Commençons par l'état initial de la base :

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

Lorsque nous exécutons maintenant le 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);

seule la première entrée sera mise à jour :

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

5.5. Mise à jour multiple

Mise à jour multiple met à jour tous les documents qui correspondent à la requête donnée.

Tout d'abord, voici l'état de la base de données avant de faire le updateMulti :

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

Maintenant, lançons le updateMulti opération :

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

Les deux objets existants seront mis à jour dans la base de données :

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

5.6. RechercherEtModifier

Cette opération fonctionne comme updateMulti , mais il renvoie l'objet avant sa modification.

Tout d'abord, voici l'état de la base de données avant d'appeler findAndModify :

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

Regardons le code d'opération réel :

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'objet utilisateur renvoyé a les mêmes valeurs que l'état initial dans la base de données.

Cependant, voici le nouvel état dans la base de données :

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

5.7. Insérer

Le upsert fonctionne sur la recherche et modification sinon créer la sémantique :si le document correspond, mettez-le à jour, ou bien créez un nouveau document en combinant l'objet requête et mise à jour.

Commençons par l'état initial de la base :

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

Exécutons maintenant le 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);

Voici l'état de la base de données après l'opération :

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

5.8. Supprimer

Nous examinerons l'état de la base de données avant d'appeler supprimer :

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

Exécutons maintenant supprimer :

mongoTemplate.remove(user, "user");

Le résultat sera comme prévu :

{
}

6. Utilisation de MongoRepository

6.1. Insérer

Tout d'abord, nous verrons l'état de la base de données avant d'exécuter l'insert :

{
}

Nous allons maintenant insérer un nouvel utilisateur :

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

Et voici l'état final de la base de données :

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

Notez comment l'opération fonctionne de la même manière que l'insert dans le MongoTemplate API.

6.2. Enregistrer Insérer

De même, enregistrez fonctionne de la même manière que la sauvegarde opération dans le MongoTemplate API.

Commençons par examiner la sémantique de l'insertion de l'opération.

Voici l'état initial de la base de données :

{
}

Maintenant, nous exécutons la save opération :

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

Cela entraîne l'ajout de l'utilisateur à la base de données :

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

Notez à nouveau comment économiser fonctionne avec insérer sémantique car nous insérons un nouvel objet.

6.3. Enregistrer Mettre à jour

Regardons maintenant la même opération mais avec la sémantique de mise à jour.

Tout d'abord, voici l'état de la base de données avant d'exécuter la nouvelle save :

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

Maintenant, nous exécutons l'opération :

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

Enfin, voici l'état de la base de données :

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

Notez à nouveau comment économiser fonctionne avec mise à jour sémantique car nous utilisons un objet existant.

6.4. Supprimer

Voici l'état de la base de données avant d'appeler supprimer :

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

Exécutons supprimer :

userRepository.delete(user);

Et voici notre résultat :

{
}

6.5. FindOne

Ensuite, voici l'état de la base de données lorsque findOne s'appelle :

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

Exécutons maintenant le findOne :

userRepository.findOne(user.getId())

Et le résultat renverra les données existantes :

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

6.6. Existe

L'état de la base de données avant d'appeler existe :

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

Maintenant, lançons exists , qui renverra bien sûr true :

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

6.7. Rechercher tout Avec Trier

L'état de la base de données avant d'appeler findAll :

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

Lançons maintenant findAll avecTrier :

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

Le résultat sera trié par nom dans l'ordre croissant :

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

6.8. Rechercher tout Avec Pageable

L'état de la base de données avant d'appeler findAll :

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

Exécutons maintenant findAll avec une requête de pagination :

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

Les utilisateurs résultants la liste ne comportera qu'un seul utilisateur :

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

7. Annotations

Enfin, passons également en revue les annotations simples que Spring Data utilise pour piloter ces opérations d'API.

Le niveau de champ @Id l'annotation peut décorer n'importe quel type, y compris long et chaîne :

@Id
private String id;

Si la valeur de @Id le champ n'est pas nul, il est stocké tel quel dans la base de données ; sinon, le convertisseur supposera que nous voulons stocker un ObjectId dans la base de données (soit ObjectId , Chaîne ou BigInteger travail).

Nous allons ensuite examiner @Document :

@Document
public class User {
    //
}

Cette annotation marque simplement une classe comme étant un objet de domaine qui doit être conservé dans la base de données, tout en nous permettant de choisir le nom de la collection à utiliser.