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
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
dependency>
配置文件的编写
server:
port: 8088
spring:
application:
name: mongdb-server
data:
mongodb:
uri: mongodb://hushang:[email protected]: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{
@Autowired
private MongoTemplate mongoTemplate;
@Test
public void testCollection(){
boolean exists = mongoTemplate.collectionExists("emp");
if (exists){
// 删除集合
mongoTemplate.dropCollection("emp");
}
// 如果不存在则创建
mongoTemplate.createCollection("emp");
}
}
@Document
@Id
@Field
@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 {
@Id
private Integer id;
@Field("username")
private String name;
@Field
private Integer age;
@Field
private Date cteateTime;
// 指定此成员变量不参与文档的序列化
@Transient
private 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);
}
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 或者 年龄小于等于30
criteria.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。
// 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()
}
@Configuration
public class TulingMongoConfig {
/**
* 定制TypeMapper去掉_class属性
* @param mongoDatabaseFactory
* @param context
* @param conversions
* @return
*/
@Bean
MappingMongoConverter 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;
}
}