Introduction to Spring Data MongoDB
I just announced the new Spring 5 modules in REST With Spring:
1. Overview
This article will be a quick and practical introduction to Spring Data MongoDB.
We’ll go over the basics using both the MongoTemplate as well as MongoRepository using practical tests to illustrate each operation.
2. MongoTemplate and MongoRepository
The MongoTemplate follows the standard template pattern in Spring and provides a ready to go, basic API to the underlying persistence engine.
The repository follows the Spring Data-centric approach and comes with more flexible and complex API operations, based on the well-known access patterns in all Spring Data projects.
For both, we need to start by defining the dependency – for example, in the pom.xml, with Maven:
1
2
3
4
5
|
< dependency > < groupId >org.springframework.data</ groupId > < artifactId >spring-data-mongodb</ artifactId > < version >1.10.4.RELEASE</ version > </ dependency > |
To check if any new version of the library has been released – track the releases here.
3. Configuration for MongoTemplate
3.1. XML Configuration
Let’s start with the simple XML configuration for the Mongo template:
1
2
|
< mongo:mongo id = "mongo" host = "localhost" /> < mongo:db-factory id = "mongoDbFactory" dbname = "test" mongo-ref = "mongo" /> |
First, we need to define the factory bean responsible for creating Mongo instances.
Next – we need to actually define (and configure) the template bean:
1
2
3
|
< bean id = "mongoTemplate" class = "org.springframework.data.mongodb.core.MongoTemplate" > < constructor-arg ref = "mongoDbFactory" /> </ bean > |
And finally we need to define a post processor to translate any MongoExceptionsthrown in @Repository annotated classes:
1
2
|
< bean class = "org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> |
3.2. Java Configuration
Let’s now create a similar configuration using Java config by extending the base class for MongoDB configuration AbstractMongoConfiguration:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Configuration public class MongoConfig extends AbstractMongoConfiguration { @Override protected String getDatabaseName() { return "test" ; } @Override public Mongo mongo() throws Exception { return new MongoClient( "127.0.0.1" , 27017 ); } @Override protected String getMappingBasePackage() { return "org.baeldung" ; } } |
Note: We didn’t need to define MongoTemplate bean in the previous configuration as it’s already defined in AbstractMongoConfiguration
We can also use our configuration from scratch without extending AbstractMongoConfiguration – as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Configuration public class SimpleMongoConfig { @Bean public Mongo mongo() throws Exception { return new MongoClient( "localhost" ); } @Bean public MongoTemplate mongoTemplate() throws Exception { return new MongoTemplate(mongo(), "test" ); } } |
4. Configuration for MongoRepository
4.1. XML Configuration
To make use of custom repositories (extending the MongoRepository) – we need to continue the configuration from section 3.1 and set up the repositories:
1
2
|
< mongo:repositories base-package = "org.baeldung.repository" mongo-template-ref = "mongoTemplate" /> |
4.2. Java Configuration
Similarly, we’ll build on the configuration we already created in section 3.2 and add a new annotation into the mix:
1
|
@EnableMongoRepositories (basePackages = "org.baeldung.repository" ) |
4.3. Create the Repository
Now, after the configuration, we need to create a repository – extending the existing MongoRepository interface:
1
2
3
|
public interface UserRepository extends MongoRepository<User, String> { // } |
Now we can auto-wire this UserRepository and use operations from MongoRepository or add custom operations.
5. Using MongoTemplate
5.1. Insert
Let’s start with the insert operation; let’s also start with a empty database:
1
2
|
{ } |
Now if we insert a new user:
1
2
3
|
User user = new User(); user.setName( "Jon" ); mongoTemplate.insert(user, "user" ); |
The database will look like this:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b4fda5830b550a8c2ca25a" ), "_class" : "org.baeldung.model.User" , "name" : "Jon" } |
5.2. Save – Insert
The save operation has save-or-update semantics: if an id is present, it performs an update, if not – it does an insert.
Let’s look at the first semantic – the insert; here’s the initial state of the database:
1
2
|
{ } |
When we now save a new user:
1
2
3
|
User user = new User(); user.setName( "Albert" ); mongoTemplate.save(user, "user" ); |
The entity will be inserted in the database:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Albert" } |
Next, we’ll look at the same operation – save – with update semantics.
5.3. Save – Update
Let’s now look at save with update semantics, operating on an existing entity:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Jack" } |
Now, when we save the existing user – we will update it:
1
2
3
4
|
user = mongoTemplate.findOne( Query.query(Criteria.where( "name" ).is( "Jack" )), User. class ); user.setName( "Jim" ); mongoTemplate.save(user, "user" ); |
The database will look like this:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Jim" } |
As you can see, in this particular example, save uses the semantics of update, because we use an object with given _id.
5.4. UpdateFirst
updateFirst updates the very first document that matches the query.
Let’s start with the initial state of the database:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Alex" }, { "_id" : ObjectId( "55b5ffa5511fee0e45ed614c" ), "_class" : "org.baeldung.model.User" , "name" : "Alex" } ] |
When we now run the updateFirst:
1
2
3
4
5
|
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 ); |
Only the first entry will be updated:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "James" }, { "_id" : ObjectId( "55b5ffa5511fee0e45ed614c" ), "_class" : "org.baeldung.model.User" , "name" : "Alex" } ] |
5.5. UpdateMulti
UpdateMulti updates all document that matches the given query.
First – here’s the state of the database before doing the updateMulti:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Eugen" }, { "_id" : ObjectId( "55b5ffa5511fee0e45ed614c" ), "_class" : "org.baeldung.model.User" , "name" : "Eugen" } ] |
Now, let’s now run the updateMulti operation:
1
2
3
4
5
|
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 ); |
Both existing objects will be updated in the database:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Victor" }, { "_id" : ObjectId( "55b5ffa5511fee0e45ed614c" ), "_class" : "org.baeldung.model.User" , "name" : "Victor" } ] |
5.6. FindAndModify
This operation works like updateMulti, but it returns the object before it was modified.
First – the state of the database before calling findAndModify:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Markus" } |
Let’s look at actual operation code:
1
2
3
4
5
|
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 ); |
The returned user object has the same values as the initial state in the database.
However, the new state in the database is:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Nick" } |
5.7. Upsert
The upsert works operate on the find and modify else create semantics: if the document is matched, update it, else create a new document by combining the query and update object
.
Let’s start with the initial state of the database:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Markus" } |
Now – let’s run the upsert:
1
2
3
4
5
|
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 ); |
Here’s the state of the database after the operation:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Nick" } |
5.8. Remove
The state of the database before calling remove:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Benn" } |
Let’s now run remove:
1
|
mongoTemplate.remove(user, "user" ); |
The result will be as expected:
1
2
|
{ } |
6. Using MongoRepository
6.1. Insert
First – the state of the database before running the insert:
1
2
|
{ } |
Now, when we insert a new user:
1
2
3
|
User user = new User(); user.setName( "Jon" ); userRepository.insert(user); |
Here’s the end state of the database:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b4fda5830b550a8c2ca25a" ), "_class" : "org.baeldung.model.User" , "name" : "Jon" } |
Note how the operation works the same as the insert in the MongoTemplate API.
6.2. Save – Insert
Similarly – save works the same as the save operation in the MongoTemplate API.
Let’s start by looking at the insert semantics of the operation; here’s the initial state of the database:
1
2
|
{ } |
Now – we execute the save operation:
1
2
3
|
User user = new User(); user.setName( "Aaron" ); userRepository.save(user); |
This results in the user being added to the database:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Aaron" } |
Note again how, in this example, save works with insert semantics, because we are inserting a new object.
6.3. Save – Update
Let’s now look at the same operation but with update semantics.
First – here’s the state of the database before running the new save:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Jack" 81*6 } |
Now – we execute the operation:
1
2
3
4
|
user = mongoTemplate.findOne( Query.query(Criteria.where( "name" ).is( "Jack" )), User. class ); user.setName( "Jim" ); userRepository.save(user); |
Finally, here is the state of the database:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b52bb7830b8c9b544b6ad5" ), "_class" : "org.baeldung.model.User" , "name" : "Jim" } |
Note again how, in this example, save works with update semantics, because we are using an existing object.
6.4. Delete
The state of the database before calling delete:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Benn" } |
Let’s run delete:
1
|
userRepository.delete(user); |
The result will simply be:
1
2
|
{ } |
6.5. FindOne
The state of the database when findOne is called:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Chris" } |
Let’s now execute the findOne:
1
|
userRepository.findOne(user.getId()) |
The result which will return the existing data:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Chris" } |
6.6. Exists
The state of the database before calling exists:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Harris" } |
Now, let’s run exists:
1
|
boolean isExists = userRepository.exists(user.getId()); |
Which of course will return true.
6.7. FindAll with Sort
The state of the database before calling findAll:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Brendan" }, { "_id" : ObjectId( "67b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Adam" } ] |
Let’s now run findAll with Sort:
1
|
List<User> users = userRepository.findAll( new Sort(Sort.Direction.ASC, "name" )); |
The result will be sorted by name in ascending order:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "67b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Adam" }, { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Brendan" } ] |
6.8. FindAll with Pageable
The state of the database before calling findAll:
1
2
3
4
5
6
7
8
9
10
11
12
|
[ { "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Brendan" }, { "_id" : ObjectId( "67b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Adam" } ] |
Let’s now execute findAll with a pagination request:
1
2
3
|
Pageable pageableRequest = new PageRequest( 0 , 1 ); Page<User> page = userRepository.findAll(pageableRequest); List<User> users = pages.getContent(); |
The result in users list will be only one user:
1
2
3
4
5
|
{ "_id" : ObjectId( "55b5ffa5511fee0e45ed614b" ), "_class" : "org.baeldung.model.User" , "name" : "Brendan" } |
7. Annotations
Finally, let’s also go over the simple annotations that Spring Data uses to drive these API operations.
1
2
|
@Id private String id; |
The field level @Id annotation can decorate any type, including long and string.
If the value of the @Id field is not null, it’s stored in the database as-is; otherwise, the converter will assume you want to store an ObjectId in the database (eitherObjectId, String or BigInteger work).
Next – @Document:
1
2
3
4
|
@Document public class User { // } |
This annotation simply marks a class as being a domain object that needs to be persisted to the database, along with allowing us to choose the name of the collection to be used.
8. Conclusion
This article was a quick but comprehensive introduction to using MongoDB with Spring Data, both via the MongoTemplate API as well as making use of MongoRepository.
The implementation of all these examples and code snippets can be found over on Github – this is a Maven-based project, so it should be easy to import and run as it is.
Introduction to Spring Data MongoDB的更多相关文章
- spring data mongodb 配置遇到的几个问题
一. mongodb 2.2版本以上的配置 spring.data.mongodb.uri = mongodb://newlook:newlook@192.168.0.109:27017/admin ...
- spring data mongodb中,如果对象中的属性不想加入到数据库字段中
spring data mongodb中,如果对象中的属性不想加入到数据库字段中,可加@Transient注解,声明为透明属性 spring data mongodb 官网帮助文档 http://ww ...
- Spring Data MongoDB example with Spring MVC 3.2
Spring Data MongoDB example with Spring MVC 3.2 Here is another example web application built with S ...
- 使用Spring访问Mongodb的方法大全——Spring Data MongoDB查询指南
1.概述 Spring Data MongoDB 是Spring框架访问mongodb的神器,借助它可以非常方便的读写mongo库.本文介绍使用Spring Data MongoDB来访问mongod ...
- Spring data mongodb 聚合,投射,内嵌数组文档分页.
尽量别直接用 DBObject ,Spring data mongodb 的api 本来就没什么多大用处,如果还直接用 DBObject 那么还需要自己去解析结果,说动做个对象映射,累不累 Spri ...
- JAVA 处理 Spring data mongodb 时区问题
Spring data mongodb 查询出结果的时候会自动 + 8小时,所以我们看起来结果是对的 但是我们查询的时候,并不会自动 + 8小时,需要自己处理 解决方法 1 @JsonFormat ...
- Spring data mongodb ObjectId ,根据id日期条件查询,省略@CreatedDate注解
先看看ObjectId 的json 结构,非常丰富,这里有唯一机器码,日期,时间戳等等,所以强烈建议ID 使用 ObjectId 类型,并且自带索引 Spring data mongodb 注解 @C ...
- Spring data mongodb @CreatedBy@LastModifiedBy@CreatedBy@LastModifiedBy SpringSecurityAuditorAware,只记录用户名
要在Spring data mongodb 中使用@CreatedBy@LastModifiedBy@CreatedBy@LastModifiedBy 这四个注解 必须实现 SpringSecuri ...
- Spring Data MongoDB 三:基本文档查询(Query、BasicQuery)(一)
一.简单介绍 Spring Data MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,上一 ...
随机推荐
- Mac adb 安装
一.下载Android studio https://developer.android.google.cn/studio/ 二.安装 首先移动 弹出下面弹框,直接点击OK 提示无法访问Android ...
- Qt5发布错误01
1.Qt5+VS2013兼容XP方法 (http://www.qtcn.org/bbs/apps.php?q=diary&a=detail&did=2047&uid=15538 ...
- rxjava rxandroid使用遇到的坑
今天在解决一个界面加载本地数据库数据的时候,使用rxjava在指定io线程操作是遇到一个问题,即使指定了在io线程操作,可是界面还是卡顿,最后通过打印线程Thread.currentThread(). ...
- mybatis 环境搭建和基本说明
mybatis介绍就不多提了,直接步入正题. 先准备好eclipse和MySQL,然后先看一下目录结构 文件和类很少,所以mybatis的搭建是非常简单的,如搭建中遇到问题可以先参考文档最后一部分的综 ...
- AtomicLong可以被原子地读取和写入的底层long值的操作
java.util.concurrent.atomic.AtomicLong类提供了可以被原子地读取和写入的底层long值的操作,并且还包含高级原子操作. AtomicLong支持基础long类型变量 ...
- [图床神器]Windows下的图片上传工具MPic
最近用hexo在github上搭建了一个静态博客,开始几天用起来感觉还挺好的,但是用了些天就觉得每次写文章插入图片就非常麻烦,而且如果图片多了的话上传和访问就很慢了.后来网上看了下发现mac下有款ip ...
- Linux CentOS7.0下JAVA安装和配置环境变量
一.前言: CentOS7.0虽然自带JDK1.7和1.8,运行“java -version”命令也可以看到版本信息,但是jdk的安装环境不全,比如缺少tool.jar和dt.jar等,这就导致“ja ...
- React中父子组件间的通信问题
1.https://blog.csdn.net/sinat_17775997/article/details/59103173 (React中父子组件间的通信问题)
- CentOS7 Could not retrieve mirrorlist http://mirrorlist.centos.org/?...
在执行命令 sudo yum clean expire-cache 清理完过期的缓存后,再执行yum install 或 update命令都失败了.原因是清理过期缓存结果不该被清理的也删掉了,可能是y ...
- hibernate的一些缺陷(转)
例如用户在系统中,保存的信息包括简要信息(用户名.联系电话.Email.性别)和一些图像信息(照片). 但是在系统设计时,我的设计方式都是遵循业务的需要,设计一个“用户”类,包含用户名. ...