MongoDB学习02:使用MongoTemplate操作MongoDB

SpringData的官方文档Spring Data MongoDB - Reference Documentation,阅读官方文档永远是最好的学习方法.

MongoTemplate的使用示例

  1. 创建SpringBoot项目,在pom.xml中添加依赖如下:

    <dependency>
        <!-- 引入Spring操作MongoDB的库 -->
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-mongodb</artifactId>
    </dependency>
    
  2. 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 + "]"; }
    }
    
  3. 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:

  1. 使用.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>
    
  2. 使用Java Config注入:

    @Configuration
    public class AppConfig {
    
        public @Bean MongoClient mongoClient() {
            return new MongoClient("localhost");
        }
    
        public @Bean MongoTemplate mongoTemplate() {
            return new MongoTemplate(mongoClient(), "数据库名");
        }
    }
    
  3. 在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字段:

  1. 使用@Id注解的属性会被映射为数据库_id字段.
  2. 名为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();    									
  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值