1. 概述

本文将快速介绍Spring Data MongoDB,我们将通过实例来演示和说明MongoTemplateMongoRepository的基础用法。

2. MongoTemplate 与 MongoRepository

我们可以使用 MongoTemplateMongoRepository 这两种方式来操作 Mongo 数据库。

MongoTemplate 遵循 Spring 中标准模板设计模式(template pattern),为应用程序持久层提供了开箱即用的基础API,如updateFirst, updateMulti, findAndModify, upsert

Repository 遵循以 Spring Data 为中心,基于DAO设计模式,提供更灵活和复杂的API。

使用这两者前我们需有先添加Maven依赖:

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

获取依赖库的最新版本,请访问Maven 中央仓库

注:如果使用 Spring Boot,请引入 spring-boot-starter-data-mongodb 依赖,可以跳过配置过程。

3. MongoTemplate 的配置

我们可以使用 XML 和 Java 代码这两种方式来配置 Mongo Template 。

3.1. XML 方式配置

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

首先,我们定义负责创建Mongo实例的mongoDbFactory

下面,配置template bean

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

最后,我们需要定义一个 post processor 来转换被 @Repository 注解类中抛出的任何MongoExceptions:

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

3.2. Java 方式配置

现在我们用Java代码方式,通过继承 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");
    }
}

备注:我们上面我们没有定义MongoTemplate bean的原因是,AbstractMongoClientConfiguration中已经为我们定义好了。

我们也可以不继承 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. MongoRepository 的配置

4.1. XML 方式配置

为使用自定义Repository(继承自MongoRepository),在 3.1节的基础上我们需要加入下面的配置:

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

4.2. Java 方式配置

同样,我们是基于3.2节的基础上,我们只需要加入下面的注解:

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

4.3. 创建 Repository

配置完成后,我们创建一个 Repository,该接口继承MongoRepository接口:

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

现在我们可以自动装配UserRepository,使用MongoRepository基类中的自定义的方法来完成数据操作。

5. 使用 MongoTemplate

5.1. Insert 插入

先从插入操作开始,现在我们有一个空的数据库:

{
}

现在插入一个新的user:

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

数据库将会变成:

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

5.2. Save – Insert 保存-插入

保存操作具有save-or-update的语义。也就是说,如果ID存在,则执行更新操作,否则执行插入操作。

先来看第一种插入的情况,下面是数据库初始状态:

{
}

当保存一个新用户时:

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

数据库中会插入一条新的记录:

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

5.3. Save – Update 保存-更新

现在看下第二种情况,保存时候,执行更新操作:

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

现在,当我们对一个已存在的用户执行保存操作时,会更新原数据:

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

数据库会变成:

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

可以看到,当ID已存在的时候,save方法实际上执行的是更新操作。

5.4. UpdateFirst

updateFirst 更新第一个匹配到的记录。

数据库初始状态:

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

当我们执行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);

只有第一条记录被更新了:

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

5.5. UpdateMulti

UpdateMulti更新所有查询到的记录.

数据库初始状态:

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

现在执行updateMulti操作:

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

所有数据都被更新了:

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

5.6. FindAndModify

FindAndModifyupdateMulti作用类似,但他它会返回更新前的对象:

调用findAndModify操作前的数据库初始状态:

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

然后执行:

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

返回的user对象的值,和数据库初始状态时的值是一样的。

然后,数据库中数据实际变成了:

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

5.7. Upsert

upsert:如果要查询的记录存在则更新,否者执行插入操作。

数据库初始状态:

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

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

执行后的数据库状态:

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

5.8. 删除

执行前,数据库:

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

执行remove删除操作:

mongoTemplate.remove(user, "user");

结果和预期一样:

{
}

6. 使用 MongoRepository

6.1. Insert 插入

插入前数据库初始状态:

{
}

插入一个新的用户:

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

插入后,数据库:

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

备注,该操作和MongoTemplate中的insert作用是一样的。

6.2. Save – Insert 保存-插入

类似的,save工作方式和MongoTemplate中的是一样的:

数据库初始状态:

{
}

执行save保存操作:

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

执行后,数据库中状态:

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

6.3. Save – Update 保存-更新

数据库初始状态:

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

执行操作:

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

最后,数据库结果:

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

6.4. 删除

删除前:

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

执行delete方法:

userRepository.delete(user);

数据库变成:

{
}

6.5. FindOne 查询单条记录

数据库中的数据:

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

执行findOne方法:

userRepository.findOne(user.getId())

查询到的结果:

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

6.6. Exists 记录是否存在

数据库中的数据:

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

执行exists方法:

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

结果返回true

6.7. FindAll 查找并排序

数据库中的数据:

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

执行findAll并排序:

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

返回的结果,按名字升序排列:

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

6.8. FindAll 查询并分页

数据库中的数据:

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

执行findAll并分页:

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

返回的users列表中,只有一条数据:

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

7. 注解

最后,我们介绍Spring Data中的一些简单注解。

@Id
private String id;

@Id注解可以修饰任何类型的字段,包括longString

如果@Id修饰的字段值不为null,则原样保存到数据库中。否者,converter假定你想要在数据中保存ObjectId(ObjectId,String或BigInteger均可)。

@Document注解:

@Document
public class User {
    //
}

该注解标注在实体类上,把Java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档名字。

8. 总结

本文快速介绍了如何使用 Spring Data 中的 MongoTemplateMongoRepository 这两种方式来操作 MongoDB。

本文中的示例和代码片段,存放在GitHub上。