springboot 操作 mongoTemplate
- maven坐标
<!-- mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
- 实体类
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document("article")
// @CompoundIndexes({
// // 复合唯一索引
// @CompoundIndex(name = "article_userId_id", def = "{'id':1,'user_id':1}", unique = true)
// })
public class ArticleModel {
//@Id
///*主键,不可重复,自带索引,可以在定义的列名上标注,需要自己生成并维护不重复的约束。
//如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。
//在实际业务中不建议自己设置主键,应交给mongo自己生成,自己可以设置一个业务id,如int型字段,用自己设置的业务id来维护相关联的表。*/
//@Document //标注在实体类上,类似于entity注解,标明由mongo来维护该表,article为mongo集合名称
//@Indexed //声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度
//@CompoundIndex //复合索引,加复合索引后通过复合索引字段查询将大大提高速度。1升序-1降序
//@Field //代表一个字段,可以不加,不加的话默认以参数名为列名
//@Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。
//@DBRef //关联另一个document对象
@Id
private Long id;
// @Indexed
private String name;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}
-
mongo数据库时间格式
-
MongoRepository
import ArticleModel;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ArticleRepository extends MongoRepository<ArticleModel, Long> {
// 自定义sql
@Query("{ 'name':{'$regex':?1}}")
public List<ArticleModel> findArticleByName(String name);
}
- 测试用例
import com.mongodb.client.result.UpdateResult;
import ArticleModel;
import ArticleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* @author qzl
* @description:
* @date 2022/10/28 20:49
*/
@RestController
@RequestMapping("mongoTest")
public class MongoTest {
@Autowired
private ArticleRepository articleRepository;
@Autowired
private MongoTemplate mongoTemplate;
@GetMapping("save")
public void save(){
ArticleModel articleModel = new ArticleModel();
articleModel.setId(1L);
articleModel.setName("文章1");
// 插入重复数据时,提示主键(_id)重复;
//批处理操作时,可以一次性插入整个数据,效率较高
// articleRepository.insert(articleModel);
// 插入重复数据时,对已有数据进行更新;
//批处理操作时,需要遍历整个数据,依次插入或更新,效率较低
articleRepository.save(articleModel);
}
@GetMapping("find")
public void find(){
ArticleModel articleModel = new ArticleModel();
articleModel.setId(1L);
articleModel.setName("文章1");
Example<ArticleModel> example = Example.of(articleModel);
// 根据model条件查询一个
ArticleModel articleModel1 = articleRepository.findOne(example).get();
// 根据ID查找
articleRepository.findById(1L);
// 根据ids查找
articleRepository.findAllById(Arrays.asList(1L,2L));
// 查找全部
List<ArticleModel> all = articleRepository.findAll(example);
// 查询全部
List<ArticleModel> all1 = articleRepository.findAll();
// 根据ID倒叙排序
Sort sort = Sort.by(Sort.Order.desc("id"));
articleRepository.findAll();
articleRepository.findAll(example, sort);
//分页
PageRequest pageOf = PageRequest.of(1, 10);
articleRepository.findAll(pageOf);
articleRepository.findAll(example,pageOf);
// mongoTemplate查询
Criteria criteria = Criteria.where("id").is(1L)// id=1
.and("id").gte(1L)// > gt < lt >= gte <= lte
.and("name").regex("*")// 正则查找
.orOperator(// or查询
Criteria.where("id").is(2L),
Criteria.where("name").is("李四")
);
// 时间间隔查询
/*
//1.数据库字段类型为ISODate时,查询时条件参数为Date类型时,程序会自动更换时区。
//2.数据库字段类型为ISODate时,查询时条件参数为时间格式字符串时,程序查询不到数据。
if (StringUtils.isNotBlank(vo.getStartTime()) && StringUtils.isNotBlank(vo.getEndTime())) {
criteria.andOperator(Criteria.where("createTime").gte(strToDateLong(vo.getStartTime()+" 00:00:00")),
Criteria.where("createTime").lt(strToDateLong(vo.getEndTime()+" 23:59:59")));
}*/
Query query = new Query(criteria);
mongoTemplate.find(query,ArticleModel.class);
// 查询分页和排序
query.with(sort);
query.with(pageOf);
mongoTemplate.find(query,ArticleModel.class);
Query querySortPage = new Query();
querySortPage.with(sort)
.skip(0) // 从第几条开始一共查几条
.limit(2); //pageSize
List<ArticleModel> users = mongoTemplate.find(querySortPage,ArticleModel.class);
// 查询总数
articleRepository.count();
articleRepository.count(example);
long count = mongoTemplate.count(new Query(), ArticleModel.class);
System.out.println(count);
long count2 = mongoTemplate.count(Query.query(Criteria.where("name").is("张三")), ArticleModel.class);
System.out.println(count2);
// 去重
//去重 参数1:查询条件 参数2:去重的字段 参数3:查询的集合 参数4:返回的类型
List<String> stringList = mongoTemplate.findDistinct(new Query(), "name", ArticleModel.class, String.class);
stringList.forEach(System.out::println);
// 使用 json 字符串方式查询
/*这种方式还可以支持 设定返回字段,不设置便全返回
*_id 默认显示
*投影中不可以同时 包容和排斥
* "{name:0,salary:0}" √ "{name:1,salary:1}" √
* "{name:1,salary:0}" ×
*/
BasicQuery basicQuery = new BasicQuery("{$or:[{name:'张三'},{id:123}]}","{id:0,name:0}");
mongoTemplate.find(basicQuery, ArticleModel.class);
}
@GetMapping("update")
public void update(){
ArticleModel articleModel = new ArticleModel();
articleModel.setId(1L);
articleModel.setName("文章1");
// 同主键会更新
articleRepository.save(articleModel);
Update update = new Update();
update.set("name","新文章");
// 更新查找到的第一条
mongoTemplate.updateFirst(Query.query(Criteria.where("name").is("文章1")),update,ArticleModel.class);
// 多条更新
mongoTemplate.updateMulti(Query.query(Criteria.where("name").is("文章1")),update,ArticleModel.class);
// upsert 没有符合条件时 插入数据
Update update1 = new Update();
update1.setOnInsert("id",5); //当插入时,指定字段值
update1.set("name","新文章");
UpdateResult upsert = mongoTemplate.upsert(Query.query(Criteria.where("name").is("文章1")), update, ArticleModel.class);
//返回值
System.out.println(upsert.getModifiedCount());//获取本次修改的记录
System.out.println(upsert.getMatchedCount());//获取本次匹配的记录
System.out.println(upsert.getUpsertedId());//获取插入数据的id
}
@GetMapping("del")
public void del(){
ArticleModel articleModel = new ArticleModel();
articleModel.setId(1L);
articleModel.setName("文章1");
articleRepository.delete(articleModel);
articleRepository.deleteAll();
articleRepository.deleteById(1L);
//删除所有
mongoTemplate.remove(new Query(),ArticleModel.class);
//条件删除
mongoTemplate.remove(Query.query(Criteria.where("name").is("王五")),ArticleModel.class);
}
@GetMapping("aggregation")
public void aggregation(){
// select
ProjectionOperation select = Aggregation.project()
.and("name").as("name")
.andExclude("_id"); // 排除ID
// where
Criteria criteria = Criteria.where("id").is(1);
Pattern pattern = Pattern.compile("^.*文章.*$", Pattern.CASE_INSENSITIVE);
criteria.and("name").regex(pattern);
MatchOperation where = Aggregation.match(criteria);
// 排序
// SortOperation sort = Aggregation.sort(Sort.by(Sort.Order.desc("mysqlId")));
// 分组
GroupOperation group = Aggregation.group("id")
.first("id").as("id")
.first("name").as("name")// 查询分组之后的字段,在project中有的
.count().as("count");
TypedAggregation<ArticleModel> liveTypedAggregation = Aggregation.newAggregation(
ArticleModel.class,
where, /*sort,*/ select, group);
// 返回对象
mongoTemplate.aggregate(liveTypedAggregation, ArticleModel.class).getMappedResults();
// 返回map
mongoTemplate.aggregate(liveTypedAggregation, Map.class).getMappedResults();
// 分页
SkipOperation skip = Aggregation.skip(getPageInfo(1,10));//跳到第几个开始
LimitOperation limit = Aggregation.limit(10);//查出多少个数据
TypedAggregation<ArticleModel> liveTypedAggregation = Aggregation.newAggregation(
ArticleModel.class,
where, select, group,skip,limit);
mongoTemplate.aggregate(liveTypedAggregation, Map.class).getMappedResults();
// $facet 多面分组,不太懂自己搜一下吧
// 总数
FacetOperation facet = Aggregation.facet(Aggregation.count().as("total")).as("total")
.and(skip, limit).as("list");
TypedAggregation<ArticleModel> liveTypedAggregation = Aggregation.newAggregation(
ArticleModel.class,
where, select, group,facet);
mongoTemplate.aggregate(liveTypedAggregation, Map.class).getMappedResults();
// 返回样式
// {"list":[{"_id":{"name":"Maven教程","mysqlId":109},"name":"文章","id":1,"count":1}],"total":[{"total":总条数}]}
}
// 每页条数,页数
public Long getPageInfo(Interger pageSize, Integer pageNum) {
long startPage = 0L;
if (null == pageNum || pageNum < 1) {
pageNum = 1;
}
if (null == pageSize || pageSize < 1) {
pageSize = 10000;
}
if (pageNum > 1) {
startPage = (long) (pageNum - 1) * pageSize;
}
return startPage;
}
/*** 添加文档主要介绍两种方式:
mongoTemplate.insert("实体对象","集合名"); 往集合插入数据的方式
mongoTemplate.save(对象,集合名(可省略)); 参数必须是对象
insert和save都适用
不写集合名,默认对象类名作为集合名(如实体类是A 集合名是a)
写集合名,则把数据写到对应集合下
1.void save(Object var1); 传入对象,不传集合名
2.void save(Object var1, String var2); 传入对象,传集合名
3.void insert(Object var1); 传入对象,不传集合名
4.void insert(Object var1, String var2); 传入对象,传集合名
5.void insert(Collection<? extends Object> var1, Class<?> var2);
下面三个方法是批量插入的实现方法
6.void insert(Collection<? extends Object> var1, String var2);
7.void insertAll(Collection<? extends Object> var1);
查询mongodb的操作:
find 和findone方法都有两种实现
1.List<T> find(Query var1, Class<T> var2) 不指定集合名
2.List<T> find(Query var1, Class<T> var2, String var3) 指定集合名
3.<T> T findOne(Query var1, Class<T> var2); 不指定集合名
4.<T> T findOne(Query var1, Class<T> var2, String var3);指定集合名
eg。
maxvalue在数据库中就对应一个集合,可以不指定集合名直接查询
Sl6512014 在数据对应很多集合 必须知道集合名才能查询出数据
*
findall
1.<T> List<T> findAll(Class<T> var1); 根据类型查询所有
2.<T> List<T> findAll(Class<T> var1, String var2); 查询集合下的该类型数据
findById:
<T> T findById(Object var1, Class<T> var2); var1 是mongodb的_id子段值
<T> T findById(Object var1, Class<T> var2, String var3); 指定集合名
更新操作:
updateFirst 更新符合条件的第一条 updateMulti 更新多个,符合条件都会更改
//修改第一条符合条件数据
1.WriteResult updateFirst(Query var1, Update var2, Class<?> var3); 指定类型
2.WriteResult updateFirst(Query var1, Update var2, String var3); 更新操作指定集合名
3.WriteResult updateFirst(Query var1, Update var2, Class<?> var3, String var4); 详细指定类型和集合名
//批量修改
4.WriteResult updateMulti(Query var1, Update var2, Class<?> var3); 指定类型
5.WriteResult updateMulti(Query var1, Update var2, String var3); 指定集合名
6.WriteResult updateMulti(Query var1, Update var2, Class<?> var3, String var4); 详细指定类型和集合名
//同updateFirst
7.WriteResult upsert(Query var1, Update var2, Class<?> var3);
8.WriteResult upsert(Query var1, Update var2, String var3);
9.WriteResult upsert(Query var1, Update var2, Class<?> var3, String var4);
删除操作:
1.WriteResult remove(Object var1);
2.WriteResult remove(Object var1, String var2);
3.WriteResult remove(Query var1, Class<?> var2); 根据条件删除
4.WriteResult remove(Query var1, Class<?> var2, String var3); 详细指定类型和集合名进行删除
5.WriteResult remove(Query var1, String var2); 指定集合名进行删除
其他一些操作:简单介绍:
//查询出后删除
<T> List<T> findAllAndRemove(Query var1, String var2); 指定集合名
<T> List<T> findAllAndRemove(Query var1, Class<T> var2); 指定类型
<T> List<T> findAllAndRemove(Query var1, Class<T> var2, String var3); 在集合下查询删除的类型数据
//查处后修改
<T> T findAndModify(Query var1, Update var2, Class<T> var3); 指定修改类型
<T> T findAndModify(Query var1, Update var2, Class<T> var3, String var4); 在集合下修改的数据类型
<T> T findAndModify(Query var1, Update var2, FindAndModifyOptions var3, Class<T> var4);
<T> T findAndModify(Query var1, Update var2, FindAndModifyOptions var3, Class<T> var4, String var5);
<T> T findAndRemove(Query var1, Class<T> var2);
<T> T findAndRemove(Query var1, Class<T> var2, String var3);
//判断是否存在
boolean exists(Query var1, String var2);
boolean exists(Query var1, Class<?> var2);
boolean exists(Query var1, Class<?> var2, String var3);
is相当于等于
in相当于sql中的in
ne相当于不等于
orOperator接受多个条件,组成or逻辑 addOperator同理
Criteria.where("author").is("mongodb") author = mongodb的数据
Criteria.where("serial").lte(500).and("st").is("1703230781").and("c").in("5.7") 多条件的查询
Criteria.where("st").exists(true) 判断这个字段存在
Criteria.where("serial").ne(1) 不等于1的数据
Criteria.where("serial").nin(1) nin 不在这个范围中
Criteria.where("serial").is(3).orOperator().is().andOperator() 追加or条件或者and条件
Criteria.where("a").regex("1") 模糊查询 可以用正则表达式
query6.with(new Sort(Sort.Direction.DESC,"a")); 按照a字段把结果降序
query6.skip(n); 跳过结果集的第n个 超过总条数就是啥都不输出 n<=0 时 查询到结束不跳过
query6.skip(n).limit(m) 跳过n条并显示m条记录
query6.addCriteria(Criteria.where("b").is("11")); 再加条件 查询子段不能是上一个query查询过的子段
query6.maxScan(6).skip(-2); 先截取六条数据再跳过两条
分页查询 query.with(new PageRequest(1, 5));
DBObject dbObject = new BasicDBObject();
//dbObject.put("name", "zhangsan"); //查询条件
BasicDBObject fieldsObject=new BasicDBObject();
//指定返回的字段
fieldsObject.put("name", true);
fieldsObject.put("age", true);
fieldsObject.put("sex", true);
Query query = new BasicQuery(dbObject,fieldsObject);
List<Person> user = mongoTemplate.find(query, Person.class);
注解
@Id
主键,不可重复,自带索引,可以在定义的列名上标注,
需要自己生成并维护不重复的约束。如果自己不设置@Id主键,
mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。
原因可参考上一篇mongo和mysql的性能对比。
@Document(collection = "sys_user")
注解@JsonFormat:后端格式化日期后返回给前端
注解 @Builder.Default:设置默认值
注解@DBRef:设置对象的关联
注解@JsonIgnore:后端返回给前端时忽略此字段
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
注解@Transient:此字段不会映射到数据库 被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。
给映射存储到 mongodb 的字段取别名
在 java bean 中字段名为 firstName,存储到 mongo 中 key 为 fName
@Field("fName")
private String firstName;
@Indexed
声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。
唯一索引的话是@Indexed(unique = true)。
也可以对数组进行索引,如果被索引的列是数组时,MongoDB会索引这个数组中的每一个元素。
也可以对整个Document进行索引,排序是预定义的按插入BSON数据的先后升序排列。
也可以对关联的对象的字段进行索引,譬如User对关联的address.city进行索引。(注解怎么写还不清楚,待查)
注解 不获取 0 Doc实体类的password 字段 1相反获取的字段 用在接口方法上面
@Query(fields = "{ 'password' : 0}")
List<Doc> findByType(String type, Pageable pageable);
****/
}