MongoDB学习02:使用MongoTemplate操作MongoDB
SpringData的官方文档Spring Data MongoDB - Reference Documentation,阅读官方文档永远是最好的学习方法.
MongoTemplate
的使用示例
-
创建SpringBoot项目,在
pom.xml
中添加依赖如下:<dependency> <!-- 引入Spring操作MongoDB的库 --> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> </dependency>
-
在
cn.maoritian.domain
包下创建实体类Preson
如下:package cn.maoritian.domain; public class Person { private String id; private String name; private int age; public String getId() {return id; } public String getName() {return name; } public int getAge() {return age; } public Person(String name, int age) {this.name = name; this.age = age; } @Override public String toString() {return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
-
在
cn.maoritian
包下创建SpringBoot启动类MongoApp
,在其main()
函数中进行对MongoDB的操作package cn.maoritian; import static org.springframework.data.mongodb.core.query.Criteria.where; import cn.maoritian.domain.Person; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; import com.mongodb.MongoClient; public class MongoApp { private static final Log log = LogFactory.getLog(MongoApp.class); public static void main(String[] args) throws Exception { MongoOperations mongoOps = new MongoTemplate(new MongoClient(), "数据库名"); mongoOps.insert(new Person("Joe", 34)); // 默认插入进名为person的collection log.info(mongoOps.findOne(new Query(where("name").is("Joe")), Person.class)); mongoOps.dropCollection("person"); } }
程序输出如下:
22:35:59.212 [main] DEBUG org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexCreator - Analyzing class class cn.maoritian.domain.Person for index information. 22:35:59.260 [main] DEBUG org.springframework.data.mongodb.core.MongoTemplate - Inserting Document containing fields: [name, age, _class] in collection: person 22:35:59.337 [main] DEBUG org.springframework.data.mongodb.core.MongoTemplate - findOne using query: { "name" : "Joe" } fields: Document{{}} for class: class cn.maoritian.domain.Person in collection: person 22:35:59.372 [main] INFO cn.maoritian.MongoApp - Person [id=5d7e4c39676d91262cdf734f, name=Joe, age=34] 22:35:59.384 [main] DEBUG framework.data.mongodb.core.MongoTemplate: 375 - Dropped collection [database.person]
MongoTemplate
的使用
向Spring容器注入MongoTemplate
下面三种方式均可向Spring容器中注入MongoTemplate
:
-
使用
.xml
文件注入:<mongo:mongo-client host="localhost" port="27017"/> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg ref="mongoClient"/> <constructor-arg name="databaseName" value="数据库名"/> </bean>
-
使用Java Config注入:
@Configuration public class AppConfig { public @Bean MongoClient mongoClient() { return new MongoClient("localhost"); } public @Bean MongoTemplate mongoTemplate() { return new MongoTemplate(mongoClient(), "数据库名"); } }
-
在SpringBoot项目中,还可以使用
.yml
文件注入spring: data: mongodb: uri: mongodb://服务器IP地址:端口号/数据库名
其中,mongodb属性对应的所有yml配置项均为
org.springframework.boot.autoconfigure.mongo.MongoProperties
类的属性,其源代码如下:package org.springframework.boot.autoconfigure.mongo; import com.mongodb.MongoClientURI; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "spring.data.mongodb") // 指明yml配置的前缀 public class MongoProperties { public static final int DEFAULT_PORT = 27017; public static final String DEFAULT_URI = "mongodb://localhost/test"; private String host; private Integer port = null; private String uri; private String database; private String authenticationDatabase; private String gridFsDatabase; private String username; private char[] password; private Class<?> fieldNamingStrategy; // get,set方法... }
字段和类型映射
_id
字段映射
MongoDB要求每个文档包含一个_id
字段,在实体类中,如下两种属性会被映射为_id
字段:
- 使用
@Id
注解的属性会被映射为数据库_id
字段. - 名为
id
的属性会被映射为数据库_id
字段.
_class
字段映射
当一个POJO对象被转换为MongoDB中的文档时,会自动在文档末尾加入一个_class
字段,其值为该POJO类的全限定类名(fully qualified classname
).
下面例子展示一个实体类与其转化为的MongoDB文档间的关系:
public class Sample {
Contact value;
}
public abstract class Contact { … }
public class Person extends Contact { … }
Sample sample = new Sample();
sample.value = new Person();
mongoTemplate.save(sample);
{
"value" : { "_class" : "cn.maoritian.Person" },
"_class" : "cn.maoritian.Sample"
}
如果不想在_class
字段中保存整个类名,可以在POJO类上使用@TypeAlias
注解,其值为_class
字段的值.
@TypeAlias("pers")
class Person {
...
}
{
"value" : { "_class" : "pers" },
"_class" : "cn.maoritian.Sample"
}
自定义类型映射
通过向Spring容器中注入MongoTypeMapper
的实现类,我们可以配置自定义类型映射.
class CustomMongoTypeMapper extends DefaultMongoTypeMapper {
//implement custom type mapping here
}
@Configuration
class SampleMongoConfiguration extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "数据库名";
}
@Override
public MongoClient mongoClient() {
return new MongoClient();
}
@Bean
@Override
public MappingMongoConverter mappingMongoConverter() throws Exception {
MappingMongoConverter mmc = super.mappingMongoConverter();
mmc.setTypeMapper(customTypeMapper());
return mmc;
}
@Bean
public MongoTypeMapper customTypeMapper() {
return new CustomMongoTypeMapper();
}
}
使用MongoTemplate
进行CRUD
对于每个实体类,MongoTemplate
会将其对象存入一个单独的集合(collection
)中,该集合的默认集合名为实体类名首字母变小写(如cn.maoritian.Person
类的所有实例默认会被存入person
集合中).
可以在实体类上加以@Document
注解,其collection
属性指定将该类的实例对象存入的集合名.
@Document(collection = "集合名")
public class Person {
// ...
}
保存(insert
/save
)文档的方法
下面三个方法可以向MongoDB中保存文档
insert(Object objectToSave)
和insert(Object objectToSave, String collectionName)
: 将objectToSave
存入MongoDB中,若与集合中现有文档发生_id
字段冲突,则报错.insertAll(Collection<Object> objectsToSave)
: 将集合objectsToSave
中的所有对象存入MongoDB中,若与集合中现有文档发生_id
字段冲突,则报错.save(Object objectToSave)
和save(Object objectToSave, String collectionName)
: 将objectToSave
存入MongoDB中,若与集合中现有文档发生_id
字段冲突,则覆盖之前的文档.
查询(query
)文档的方法
下面五个方法可以查询MongoDB中的文档
<T> List<T> findAll(Class<T> entityClass)
和<T> List<T> findAll(Class<T> entityClass, String collectionName)
: 查询所有T类型的文档.<T> T findOne(Query query, Class<T> entityClass)
和T findOne(Query query, Class<T> entityClass, String collectionName)
: 查询一个满足query
条件的文档.<T> T findById(Object id, Class<T> entityClass)
和<T> T findById(Object id, Class<T> entityClass, String collectionName)
: 通过id
查询文档.<T> List<T> find(Query query, Class<T> entityClass)
和<T> List<T> find(Query query, Class<T> entityClass, String collectionName)
: 查询所有满足query
条件的文档.
List<Person> result = mongoTemplate.find(query(where("age").lt(50)
.and("accounts.balance").gt(1000.00d)), Person.class);
通过Query.addCriteria()
方法,我们可以使用Criteria
对象构造Query
对象.Criteria
的方法与MongoDB的操作符一一对应如下:
Criteria 的方法 | 对应的MongoDB操作符 |
---|---|
Criteria all(Object o) | $all |
Criteria and(String key) | 对key 增加链式Criteria |
Criteria andOperator(Criteria… criteria) | $and |
Criteria elemMatch(Criteria c) | $elemMatch |
Criteria exists(boolean b) | $exists |
Criteria gt(Object o) | $gt |
Criteria gte(Object o) | $gte |
Criteria in(Object… o) | $in |
Criteria in(Collection<?> collection) | $in |
Criteria is(Object o) | field matching({ key:value } ).顺序敏感(field sensitive ) |
Criteria lt(Object o) | $lt |
Criteria lte(Object o) | $lte |
Criteria mod(Number value, Number remainder) | $mod |
Criteria ne(Object o) | $ne |
Criteria nin(Object… o) | $nin |
Criteria norOperator(Criteria… criteria) | $nor |
Criteria not() | $not |
Criteria orOperator(Criteria… criteria) | $or |
Criteria regex(String re) | $regex |
Criteria size(int s) | $size |
Criteria type(int t) | $type |
修改(update
)文档的方法
下面两个方法可以修改MongoDB中的文档
updateFirst(Query query, Update update, Class<?> entityClass)
和updateFirst(Query query, Update update, String collectionName)
: 修改第一个满足条件的文档.updateMulti(Query query, Update update, Class<?> entityClass)
和updateMulti(Query query, Update update, String collectionName)
: 修改第一个满足条件的文档.
参数的意义如下:
query
: 表示查询条件update
: 表示修改操作
import static org.springframework.data.mongodb.core.query.Criteria.where;
import static org.springframework.data.mongodb.core.query.Query;
import static org.springframework.data.mongodb.core.query.Update;
WriteResult wr = mongoTemplate.updateMulti(new Query(where("accounts.accountType").is(Account.Type.SAVINGS)),
new Update().inc("accounts.$.balance", 50.00), Account.class);
Update
对象可以通过链式调用添加修改操作.常见的方法如下,与MongoDB的修改操作符有一一对应的关系
Update 的实例方法 | 对应的MongoDB操作符 |
---|---|
Update addToSet(String key, Object value) | $addToSet |
Update currentDate(String key) | $currentDate |
Update currentTimestamp(String key) | $currentDate |
Update inc(String key, Number inc) | $inc |
Update max(String key, Object max) | $max |
Update min(String key, Object min) | $min |
Update multiply(String key, Number multiplier) | $mul |
Update pop(String key, Update.Position pos) | $pop |
Update pull(String key, Object value) | $pull |
Update pullAll(String key, Object[] values) | $pullAll |
Update push(String key, Object value) | $push |
Update pushAll(String key, Object[] values) | $pushAll |
Update rename(String oldName, String newName) | $rename |
Update set(String key, Object value) | $set |
Update setOnInsert(String key, Object value) | $setOnInsert |
Update unset(String key) | $unset |
下面四个例子展示了Update
对象和MongoDB操作符的对应关系:
new Update().push("category").each("spring", "data")
new Update().push("key").atPosition(Position.FIRST).each(Arrays.asList("Arya", "Arry", "Weasel"));
new Update().push("key").slice(5).each(Arrays.asList("Arya", "Arry", "Weasel"));
new Update().addToSet("values").each("spring", "data", "mongodb");
{ $push : { "category" : { "$each" : [ "spring" , "data" ] } } }
{ $push : { "key" : { "$position" : 0 , "$each" : [ "Arya" , "Arry" , "Weasel" ] } } }
{ $push : { "key" : { "$slice" : 5 , "$each" : [ "Arya" , "Arry" , "Weasel" ] } } }
{ $addToSet : { "values" : { "$each" : [ "spring" , "data" , "mongodb" ] } } }
更新插入(upsert
)文档的方法
更新插入upsert(Query query, Update update, Class<?> entityClass)
和upsert(Query query, Update update, String collectionName)
方法,执行的是保存或修改过程.
- 若根据
query
条件能查到文档,则执行updateFirst()
操作 - 若根据
query
条件不能查到文档,则执行insert()
操作
mongoTemplate.upsert(query(where("ssn").is(1111).and("firstName").is("Joe").and("Fraizer").is("Update")),
update("address", addr), Person.class);
查询并修改(find and modify
)文档的方法
查询并修改find and modify
有如下四个重载方法:
<T> T findAndModify(Query query, Update update, Class<T> entityClass);
<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);
<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass, String collectionName);
其中options
参数封装了修改操作的一些选项如下:
returnNew
属性取值true|false
,默认值为false
.表示返回的是修改前的查询结果还是修改后的结果upsert
属性取值true|false
,默认值为false
.取值为true
表示执行upsert
操作;取值为false
表示执行update
操作.remove
属性取值true|false
,默认值为false
.表示是否删除掉查询结果
mongoTemplate.insert(new Person("Harry", 23));
Query query1 = new Query(Criteria.where("firstName").is("Harry"));
Update update1 = new Update().inc("age", 1);
Person p1 = mongoTemplate.findAndModify(query1, update1, Person.class);
// 得到 Person [id=5d90533e74fa159cdb13cae0, firstName=Harry, age=1]
Query query2 = new Query(Criteria.where("firstName").is("Mary"));
Update update2 = new Update().inc("age", 1);
Person p2 = mongoTemplate.findAndModify(query2, update2, new FindAndModifyOptions().returnNew(true).upsert(true), Person.class);
// 得到 Person [id=5d9054b574fa159cdb13cae1, firstName=Mary, age=1]
查询并删除(find and remove
)文档的方法
查询并删除文档的方法findAndRemove()
与findAndModify()
的使用几乎完全相同,有以下几个重载的方法:
<T> List<T> findAllAndRemove(Query query, String collectionName)
<T> List<T> findAllAndRemove(Query query, Class<T> entityClass)
<T> List<T> findAllAndRemove(Query query, Class<T> entityClass, String collectionName)
查询并替换(find and replace
)文档的方法
与findAndModify()
方法类似,findAndReplace()
方法也需要指定一个option
Optional<User> result = template.update(Person.class)
.matching(query(where("firstame").is("Tom")))
.replaceWith(new Person("Dick"))
.withOptions(FindAndReplaceOptions.options().upsert())
.as(User.class)
.findAndReplace();