文章目录
- SpringBoot整合MongoDB
- 环境准备
- 文档操作
- 相关注解
- 创建实体
- 添加文档
- 查询文档
- 更新文档
- 删除文档
- 小技巧:如何去掉_class属性
SpringBoot整合MongoDB
https://docs.spring.io/spring-boot/docs/current/reference/html/data.html#data.nosql.mongodb.repositories
注意关注MongoDB服务端和客户端之间的版本兼容问题:https://docs.spring.io/spring-data/mongodb/reference/preface.html
环境准备
- 引入依赖
<!--spring data mongodb-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
-
配置文件的编写
server:port: 8088spring:application:name: mongdb-serverdata:mongodb:uri: mongodb://hushang:123456@192.168.75.100:27017/test?authSource=admin # uri等同于下面的配置 # database: test # host: 192.168.75.100 # port: 27017 # username: hushang # password: 123456 # authentication-database: admin
连接配置参考文档:https://docs.mongodb.com/manual/reference/connection-string/
-
测试
// LearnMongodbApplicationTest为我们在测试包下定义的主启动类 public class MongoTemplateTests extends LearnMongodbApplicationTest{@Autowiredprivate MongoTemplate mongoTemplate;@Testpublic void testCollection(){boolean exists = mongoTemplate.collectionExists("emp");if (exists){// 删除集合mongoTemplate.dropCollection("emp");}// 如果不存在则创建mongoTemplate.createCollection("emp");} }
文档操作
相关注解
-
@Document
- 修饰范围: 用在类上
- 作用: 用来映射这个类的一个对象为mongo中一条文档数据。
- 属性:( value 、collection )用来指定操作的集合名称
-
@Id
- 修饰范围: 用在成员变量、方法上
- 作用: 用来将成员变量的值映射为文档的_id的值
-
@Field
- 修饰范围: 用在成员变量、方法上
- 作用: 用来将成员变量及其值映射为文档中一个key:value对。
- 属性:( name , value )用来指定在文档中 key的名称,默认为成员变量名
-
@Transient
- 修饰范围:用在成员变量、方法上
- 作用:用来指定此成员变量不参与文档的序列化
创建实体
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;import java.util.Date;/*** @Description: 临时emp 集合中的文档实体对象* @Author 胡尚* @Date: 2024/7/27 19:09*/
@Data
@Document("emp") // 需要和mongodb中的collection名对应上
@AllArgsConstructor
@NoArgsConstructor
public class Employee {@Idprivate Integer id;@Field("username")private String name;@Fieldprivate Integer age;@Fieldprivate Date cteateTime;// 指定此成员变量不参与文档的序列化@Transientprivate String script;
}
添加文档
insert方法返回值是新增的Document对象,里面包含了新增后_id
的值。如果集合不存在会自动创建集合。
通过Spring Data MongoDB还会给集合中多加一个_class
的属性,存储新增时Document对应Java中类的全限定路径。
这么做为了查询时能把Document转换为Java类型。
@Test
public void testInsertDocument(){Employee user = new Employee(1, "hushang", 25, new Date(), "这是一个测试数据");// 添加文档// save() 方法 _id存在时进行更新操作Employee userSave = mongoTemplate.save(user);System.out.println(userSave);// insert() _id存在时抛异常 支持批量操作//Employee userSave = mongoTemplate.insert(user);}
此时我mongodb中保存的结果为
test> db.emp.find()
[{_id: 1,username: 'hushang',age: 25,cteateTime: ISODate("2024-07-27T11:19:15.014Z"),_class: 'com.hs.learn.entity.Employee'}
]
我们在试试insert()方法的批量插入
@Test
public void testInsertDocument(){ArrayList<Employee> employeeArrayList = new ArrayList<>();employeeArrayList.add(new Employee(2, "hushang", 25, new Date(), ""));employeeArrayList.add(new Employee(3, "hushang", 25, new Date(), ""));employeeArrayList.add(new Employee(4, "hushang", 25, new Date(), ""));// 插入多条记录mongoTemplate.insert(employeeArrayList, Employee.class);
}
- 插入重复数据时: insert报 DuplicateKeyException提示主键重复; save对已存在的数据进行更新。
- 批处理操作时: insert可以一次性插入所有数据,效率较高;save需遍历所有数据,一次插入或更新,效率较低。
查询文档
Criteria
是标准查询的接口,可以引用静态的Criteria.where
的把多个条件组合在一起,就可以轻松地将多个方法标准和查询连接起来,方便我们操作查询语句。
@Test
public void testFind(){log.info("==========查询所有文档===========");List<Employee> employeeList = mongoTemplate.findAll(Employee.class);employeeList.forEach(System.out::println);log.info("==========根据_id查询===========");Employee mongoTemplateById = mongoTemplate.findById(1, Employee.class);System.out.println(mongoTemplateById);log.info("==========findOne返回第一个文档===========");Employee employeeByOne = mongoTemplate.findOne(new Query(), Employee.class);System.out.println(employeeByOne);log.info("==========条件查询===========");//new Query() 表示没有条件//查询年龄大于等于18的数据Query query1 = new Query(Criteria.where("age").gt(18));//查询年龄大于等于18 小于28的数据Query query2 = new Query(Criteria.where("age").gt(18).lt(28));// 正则查询(模糊查询) java中正则不需要有//// 这里用 name 或者是 username 都能查询Query query3 = new Query(Criteria.where("name").regex("hu"));log.info("==========and or 多条件查询===========");Criteria criteria = new Criteria();// 查询年龄大于18 并且 name为hushang的// criteria.andOperator(Criteria.where("age").gt(18), Criteria.where("name").is("hushang"));// 查询name为hushang 或者 年龄小于等于30criteria.orOperator(Criteria.where("name").is("hushang"), Criteria.where("age").lte(30));Query query4 = new Query(criteria);System.out.println(mongoTemplate.find(query4, Employee.class));log.info("==========sort排序===========");// 安装年龄进行降序排序Query query5 = new Query();query5.with(Sort.by(Sort.Order.desc("age")));log.info("======skip limit 分页 =======");// skip用于指定跳过记录数,limit则用于限定返回结果数量。// 安装年龄进行排序,在进行分页Query query6 = new Query();query6.with(Sort.by(Sort.Order.desc("age"))).skip(1).limit(2);}
@Test
public void testFindByJson(){// 等值查询 查询username为hushang的文档String json = "{username: 'hushang'}";// 多条件查询String json2 = "{$and: [{age: {$gt: 18}},{age: {$lt: 28}}]}";BasicQuery basicQuery = new BasicQuery(json2);List<Employee> employees = mongoTemplate.find(basicQuery, Employee.class);employees.forEach(System.out::println);}
更新文档
在Mongodb中无论是使用客户端API还是使用Spring Data,更新返回结果一定是受行数影响。如果更新后的结果和更新前的结果是相同,返回0。
- updateFirst() 只更新满足条件的第一条记录
- updateMulti() 更新所有满足条件的记录
- upsert() 没有符合条件的记录则插入数据
// Update对象是这个包下的 import org.springframework.data.mongodb.core.query.Update;@Test
public void testUpdate(){//query设置查询条件Query query = new Query(Criteria.where("username").is("hushang"));log.info("==========更新前===========");List<Employee> employees = mongoTemplate.find(query, Employee.class);employees.forEach(System.out::println);Update update = new Update();update.set("age", 18);// updateFirst()只更新满足条件的一条文档// UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Employee.class);// updateMulti()更新所有满足条件的文档// UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Employee.class);// upsert() 没有符合条件的记录则插入数据// UpdateResult updateResult = mongoTemplate.upsert(query, update, Employee.class);}
删除文档
@Test
public void testDelete(){//删除所有文档//mongoTemplate.remove(new Query(),Employee.class);//条件删除Query query = new Query(Criteria.where("age").gte(45));mongoTemplate.remove(query,Employee.class);// mongodb还有下面两个移除相关的方法// mongoTemplate.findAllAndRemove()// mongoTemplate.findAndRemove()
}
小技巧:如何去掉_class属性
@Configuration
public class TulingMongoConfig {/*** 定制TypeMapper去掉_class属性* @param mongoDatabaseFactory* @param context* @param conversions* @return*/@BeanMappingMongoConverter mappingMongoConverter(MongoDatabaseFactory mongoDatabaseFactory,MongoMappingContext context, MongoCustomConversions conversions){DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDatabaseFactory);MappingMongoConverter mappingMongoConverter =new MappingMongoConverter(dbRefResolver,context);mappingMongoConverter.setCustomConversions(conversions);//构造DefaultMongoTypeMapper,将typeKey设置为空值mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));return mappingMongoConverter;}}