sql >> Databasteknik >  >> NoSQL >> MongoDB

Introduktion till Spring Data MongoDB

1. Översikt

Den här artikeln kommer att vara en snabb och praktisk introduktion till Spring Data MongoDB.

Vi går igenom grunderna med både MongoTemplate samt MongoRepository , med praktiska exempel för att illustrera varje operation.


Mer läsning:

Geospatialt stöd i MongoDB

Ta en titt på hur du lagrar, indexerar och söker geospatial data med MongoDB Läs mer →

Spring Boot Integration Testing with Embedded MongoDB

Lär dig hur du använder Flapdoodles inbyggda MongoDB-lösning tillsammans med Spring Boot för att köra MongoDB-integreringstester smidigt. Läs mer →

2. MongoTemplate och MongoRepository

Mongo-mallen följer standardmallmönstret under våren och tillhandahåller ett färdigt, grundläggande API till den underliggande persistensmotorn.

Förvaret följer Spring Data-centrerad tillvägagångssätt och kommer med mer flexibla och komplexa API-operationer, baserade på de välkända åtkomstmönstren i alla Spring Data-projekt.

För båda måste vi börja med att definiera beroendet – till exempel i pom.xml , med Maven:

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

För att kontrollera om någon ny version av biblioteket har släppts, spåra utgivningarna här.

3. Konfiguration för MongoTemplate

3.1. XML-konfiguration

Låt oss börja med den enkla XML-konfigurationen för Mongo-mallen:

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

Vi måste först definiera fabriksbönan som är ansvarig för att skapa Mongo-instanser.

Därefter måste vi faktiskt definiera (och konfigurera) mallbönan:

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

Och slutligen måste vi definiera en efterbehandlare för att översätta alla MongoExceptions kastas i @Repository kommenterade klasser:

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

3.2. Java-konfiguration

Låt oss nu skapa en liknande konfiguration med Java-konfiguration genom att utöka basklassen för MongoDB-konfiguration 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");
    }
}

Observera att vi inte behövde definiera MongoTemplate bean i den tidigare konfigurationen eftersom den redan är definierad i AbstractMongoClientConfiguration .

Vi kan också använda vår konfiguration från början utan att utöka 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. Konfiguration för MongoRepository

4.1. XML-konfiguration

För att använda anpassade arkiv (som utökar MongoRepository ), måste vi fortsätta konfigurationen från avsnitt 3.1. och ställ in arkiven:

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

4.2. Java-konfiguration

På samma sätt kommer vi att bygga vidare på konfigurationen som vi redan skapat i avsnitt 3.2. och lägg till en ny kommentar i mixen:

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

4.3. Skapa arkivet

Efter konfigurationen måste vi skapa ett arkiv – förlänga det befintliga MongoRepository gränssnitt:

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

Nu kan vi automatiskt koppla detta UserRepository och använd operationer från MongoRepository eller lägg till anpassade operationer.

5. Använder MongoTemplate

5.1. Infoga

Låt oss börja med insert-operationen samt en tom databas:

{
}

Om vi ​​nu infogar en ny användare:

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

databasen kommer att se ut så här:

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

5.2. Spara – Infoga

spara operationen har spara-eller-uppdatera semantik:om ett id finns, utför den en uppdatering, och om inte, infogar den.

Låt oss titta på den första semantiken — infogningen.

Här är det initiala tillståndet för databasen:

{
}

När vi nu spara en ny användare:

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

enheten kommer att infogas i databasen:

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

Därefter ska vi titta på samma operation – spara — med uppdateringssemantik.

5.3. Spara – Uppdatera

Låt oss nu titta på spara med uppdateringssemantik, som fungerar på en befintlig enhet:

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

När vi spara den befintliga användaren kommer vi att uppdatera den:

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

Databasen kommer att se ut så här:

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

Vi kan se att i det här exemplet spara använder semantiken för uppdatering eftersom vi använder ett objekt med angivet _id .

5.4. UpdateFirst

updateFirst uppdaterar det allra första dokumentet som matchar frågan.

Låt oss börja med databasens initiala tillstånd:

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

När vi nu kör 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);

endast den första posten kommer att uppdateras:

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

5.5. UpdateMulti

UpdateMulti uppdaterar alla dokument som matchar den givna frågan.

Först, här är tillståndet för databasen innan du gör updateMulti :

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

Låt oss nu köra updateMulti operation:

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

Båda befintliga objekten kommer att uppdateras i databasen:

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

5.6. FindAndModify

Denna operation fungerar som updateMulti , men det returerar objektet innan det ändrades.

För det första är detta tillståndet för databasen innan findAndModify anropas :

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

Låt oss titta på den faktiska operationskoden:

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

Det returnerade användarobjektet har samma värden som initialtillståndet i databasen.

Detta är dock det nya tillståndet i databasen:

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

5.7. Upsert

upsert fungerar på hitta och modifiera annat skapa semantik :om dokumentet matchas, uppdatera det eller skapa ett nytt dokument genom att kombinera frågan och uppdateringsobjektet.

Låt oss börja med databasens initiala tillstånd:

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

Låt oss nu köra 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);

Här är tillståndet för databasen efter operationen:

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

5.8. Ta bort

Vi kommer att titta på tillståndet för databasen innan vi anropar remove :

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

Låt oss nu köra ta bort :

mongoTemplate.remove(user, "user");

Resultatet blir som förväntat:

{
}

6. Använder MongoRepository

6.1. Infoga

Först kommer vi att se tillståndet för databasen innan vi kör insert :

{
}

Nu kommer vi att infoga en ny användare:

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

Och här är sluttillståndet för databasen:

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

Notera hur operationen fungerar på samma sätt som infogningen i MongoTemplate API.

6.2. Spara Infoga

På samma sätt spara fungerar på samma sätt som spara operation i MongoTemplate API.

Låt oss börja med att titta på infogningens semantik av operationen.

Här är det initiala tillståndet för databasen:

{
}

Nu kör vi spara operation:

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

Detta resulterar i att användaren läggs till i databasen:

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

Notera igen hur du spara fungerar med insert semantik eftersom vi infogar ett nytt objekt.

6.3. Spara Uppdatera

Låt oss nu titta på samma operation men med uppdatera semantik.

Först, här är tillståndet för databasen innan du kör det nya spara :

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

Nu kör vi operationen:

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

Slutligen, här är tillståndet för databasen:

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

Notera igen hur du spara fungerar med uppdatering semantik eftersom vi använder ett befintligt objekt.

6.4. Ta bort

Här är tillståndet för databasen innan du anropar delete :

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

Låt oss köra delete :

userRepository.delete(user);

Och här är vårt resultat:

{
}

6.5. FindOne

Därefter är detta tillståndet för databasen när findOne heter:

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

Låt oss nu köra findOne :

userRepository.findOne(user.getId())

Och resultatet kommer att returnera befintliga data:

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

6.6. Finns

Databasens tillstånd före anrop finns :

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

Låt oss nu köra exists , vilket naturligtvis kommer att returnera true :

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

6.7. Hitta alla Med Sortera

Databasens tillstånd innan findAll anropas :

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

Låt oss nu köra findAll med Sortera :

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

Resultatet kommer att sorteras efter namn i stigande ordning :

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

6.8. Hitta alla Med Sökbar

Databasens tillstånd innan findAll anropas :

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

Låt oss nu köra findAll med en pagineringsbegäran:

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

De resulterande användarna listan kommer bara att vara en användare:

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

7. Anteckningar

Slutligen, låt oss också gå igenom de enkla kommentarerna som Spring Data använder för att driva dessa API-operationer.

Fältnivån @Id anteckningar kan dekorera vilken typ som helst, inklusive lång och sträng :

@Id
private String id;

Om värdet på @Id fältet är inte null, det lagras i databasen som det är; annars kommer omvandlaren att anta att vi vill lagra ett ObjectId i databasen (antingen ObjectId , Sträng eller BigInteger arbete).

Vi ska nästa titta på @Document :

@Document
public class User {
    //
}

Den här anteckningen markerar helt enkelt en klass som ett domänobjekt som måste finnas kvar i databasen, tillsammans med att vi kan välja namnet på samlingen som ska användas.


  1. Åtgärda sidfel i MongoDB

  2. Bör du aktivera MongoDB Journaling?

  3. Är master alltid omdisponerad instans med minsta prioritet?

  4. skapa registrerings- och inloggningsformulär i node.js och mongodb