利用MongoTemplate 简单实现MongoDB 增删改查
Posted wb54979
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用MongoTemplate 简单实现MongoDB 增删改查相关的知识,希望对你有一定的参考价值。
1:MongoDB-maven仓库
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2:配置文件application.properties添加MongoDB配置
#MongoDB
spring.data.mongodb.uri=mongodb://127.0.0.1:27017/test-MongoDB
3:通过MongoTemplate 简单的实现 增删改
import com.alibaba.fastjson.JSON;
import com.base.utils.AssertUtils;
import com.base.dto.other.BaseMongoUpdateDTO;
import com.base.util.ObjectParseUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
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.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* author : wb
* File Name: GenericMongoCrudApplication
* Package Name: com.base.domain.mongo
* Date: 2022/5/16 13:35
* Copyright (c) 2022,All Rights Reserved.
*/
@Service
public class GenericMongoCrudApplication
private Logger logger = LoggerFactory.getLogger(GenericMongoCrudApplication.class);
private MongoTemplate mongoTemplate;
public GenericMongoCrudApplication(MongoTemplate mongoTemplate)
this.mongoTemplate = mongoTemplate;
/**
* @description: 根据ID修改数据
* @param:
* @return:
**/
public void modifyDataAccordingToId(BaseMongoUpdateDTO updateDTO)
logger.info("变更数据入参:", JSON.toJSONString(updateDTO));
String primaryKey = ObjectParseUtils.parsePrimaryKey(updateDTO.getUpdateObj());
AssertUtils.hasText(primaryKey,"缺少变更数据唯一标识");
Object primaryVal = ObjectParseUtils.getFieldValueByName(primaryKey,updateDTO.getUpdateObj());
AssertUtils.notNull(primaryVal,"缺少变更数据唯一标识");
Query query = new Query();
query.addCriteria(Criteria.where(primaryKey).is(primaryVal));
logger.info("变更数据Query:", JSON.toJSONString(query));
Update update = new Update();
if(Objects.nonNull(updateDTO.getIncObj()))
List<String> attrs = ObjectParseUtils.getFiledName(updateDTO.getIncObj());
attrs.forEach(key->
Object obj = ObjectParseUtils.getFieldValueByName(key,updateDTO.getIncObj());
if(Objects.nonNull(obj))
Integer num = (Integer)obj;
update.inc(key, num == 0 ? 1 : num);
);
if(Objects.nonNull(updateDTO.getUpdateObj()))
List<String> attrs = ObjectParseUtils.getFiledName(updateDTO.getUpdateObj());
attrs.forEach(key->
Object obj = ObjectParseUtils.getFieldValueByName(key,updateDTO.getUpdateObj());
String val = JSON.toJSONString(obj);
if(Objects.nonNull(obj) && !"null".equals(val)
&& StringUtils.isNotEmpty(val))
update.set(key, obj);
);
logger.info("变更数据Update:", JSON.toJSONString(update));
this.mongoTemplate.updateFirst(query, update, updateDTO.getClazz());
/**
* @description: 插入数据
* @param:
* @return:
**/
public void insertData(Object clazz)
logger.info("插入数据:",JSON.toJSONString(clazz));
this.mongoTemplate.insert(clazz);
/**
* @description: 删除消息数据
* @param: id
**/
public void delete(Query query,Class<?> clss)
this.mongoTemplate.remove(query,clss);
/**
* @description 批量插入
* @param list
* @param clazz
*/
public void batchInsert(List<?> list, Class<?> clazz)
this.mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz).insert(list).execute();
4:调用封装简陋的通用类进行 增删改
@SpringBootTest
@RunWith(SpringRunner.class)
public class FailMqRecordApplicationTest
@Autowired
private GenericMongoCrudApplication genericMongoCrudApplication;
/**
* 新增
*/
@Test
public void testAdd()
MessageNoticePO po = new MessageNoticePO();
//po.set 省略N步set操作
this.genericMongoCrudApplication.insertData(po);
/**
* 批量新增
*/
@Test
public void testBatchAdd()
List<MessageNoticePO> list = new ArrayList();
//po.set 省略N步set操作
this.genericMongoCrudApplication.batchInsert(list,MessageNoticePO.class);
/**
* 删除
*/
@Test
public void delete()
Query query = new Query();
Criteria criteria = new Criteria();
criteria.and("_id").is(111);
query.addCriteria(criteria);
this.genericMongoCrudApplication.delete(query,MessageNoticePO.class);
/**
* 修改
*/
@Test
public boolean modifyData()
BaseMongoUpdateDTO updateDTO = new BaseMongoUpdateDTO();
updateDTO.setClazz(MessageNoticePO.class);
MessageNoticePO no = new MessageNoticePO();
no.setId(111);
//省略N步要编辑的set操作
updateDTO.setUpdateObj(no);
updateDTO.setIncObj(new MessageNoticePO(retryCount));
this.genericMongoCrudApplication.modifyDataAccordingToId(updateDTO);
5:操作新增改的对象
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.redis.core.index.Indexed;
import java.io.Serializable;
import java.util.Date;
/**
* author : wb
* File Name: MessageNoticePO
* Package Name: com.base.domain.po.mongo
* Date: 2022/5/18 13:43
* Copyright (c) 2022,All Rights Reserved.
*/
@Document(collection = "message_notice")
public class MessageNoticePO implements Serializable
/**
* '主键'
*/
@Id
private Long messageId;
/**
* 消息分组ID
**/
@Field
@Indexed
private Long messageGroupId;
//省略N个字段 以及set get
6:统一修改的入参对象
import java.io.Serializable;
/**
* author : wb
* File Name: BaseMongoUpdateDTO
* Package Name: com.base.dto.other
* Date: 2022/5/16 13:38
* Copyright (c) 2022,All Rights Reserved.
*/
public class BaseMongoUpdateDTO<T> implements Serializable
/**
* 要修改的属性+值
*/
private T updateObj;
/**
* 要修改的具体操作对象
*/
private Class<?> clazz;
/**
* 需要特殊操作的
* 实现数字修改,添加or减少
* 例如 原本数据库是 1 这里传递 表字段 num = 2 表示当前字段取数据库原有的自动+2
*/
private T incObj;
public Class<?> getClazz()
return clazz;
public void setClazz(Class<?> clazz)
this.clazz = clazz;
public T getUpdateObj()
return updateObj;
public void setUpdateObj(T updateObj)
this.updateObj = updateObj;
public T getIncObj()
return incObj;
public void setIncObj(T incObj)
this.incObj = incObj;
7:查询实现简单简单阐述一下 MongoDB 对于 > < null not null的实现
mongoDB大于小于符号对应:
> 大于 $gt
< 小于 $lt
>= 大于等于 $gte
<= 小于等于 $lte
要查询同一个时间多个约束可能出现的error:
org.springframework.data.mongodb.InvalidMongoDbApiUsageException:
Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'createdDate' expression specified as 'createdDate:
Document$lt=2018-01-06'. Criteria already contains 'createdDate: Document$gte=2017-12-31'.
解决办法:
要查询同一个字段多个约束需要用andOperator:
Query query = new Query(
Criteria.where("ip").is(ip)
.andOperator(
Criteria.where("createdDate").lt(endDate),
Criteria.where("createdDate").gte(startDate)));
MongoDB中的null 和not null
1、查询全部数据
> db.foo.find()
"_id" : ObjectId("544db3565d92133398a80daa"), "a" : 1, "name" :null
"_id" : ObjectId("544db3565d92133398a80daa"), "a" : 1, "name" : "ZZZZZ"
"_id" : ObjectId("5448ac1d735969c5f8386958"), "a" : 4
"_id" : ObjectId("544854ee3966c0424b50b46d"), "b" : 2
"_id" : ObjectId("544855ce735969c5f8386952"), "pwd" : "1212", "username" : "zhangsan
"_id" : ObjectId("544855e8735969c5f8386953"), "username" : "lisi", "pwd" : "222"
"_id" : ObjectId("5448ae4c735969c5f838695d"), "username" : "tom", "age" : 23
2、查询name值为null
查询name为null,会查询出name字段不存的数据,如下:
> db.foo.find(name:$in:[null])
"_id" : ObjectId("544db3565d92133398a80daa"), "a" : 1, "name" : null
"_id" : ObjectId("5448ac1d735969c5f8386958"), "a" : 4
"_id" : ObjectId("544854ee3966c0424b50b46d"), "b" : 2
"_id" : ObjectId("544855ce735969c5f8386952"), "pwd" : "1212", "username" : "zhangsan
"_id" : ObjectId("544855e8735969c5f8386953"), "username" : "lisi", "pwd" : "222"
查询也可用:> db.foo.find(name:null)
除第一条记录外,其它记录不存在name字段
3、name字段加上 $exists:true
> db.foo.find(name:$in:[null],$exists:true)
"_id" : ObjectId("544db3565d92133398a80daa"), "a" : 1, "name" :null
4、查询name为不为空时(not null )
> db.foo.find(name:$ne:null)
"_id" : ObjectId("544db3b45d92133398a80dab"), "a" : 1, "name" : "zzz"
8:简陋封装的通用查询类
import com.alibaba.fastjson.JSON;
import com.base.search.Pager;
import com.base.dto.other.PageListDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* author : wb
* File Name: GenericMongoQuery
* Package Name: com.base.domain.mongo
* Date: 2022/5/17 15:24
* Copyright (c) 2022,All Rights Reserved.
*/
@Service
public class GenericMongoQuery
private Logger logger = LoggerFactory.getLogger(GenericMongoQuery.class);
private MongoTemplate mongoTemplate;
public GenericMongoQuery(MongoTemplate mongoTemplate)
this.mongoTemplate = mongoTemplate;
/**
* @description: 根据主键id查询返回
* @param
**/
public <T> T getOne(Long id,Class<T> returnClszz)
return this.mongoTemplate.findById(id, returnClszz);
/**
* @description: 根据主键query查询返回
* @param
**/
public <T> T queryOne(Query query,Class<T> returnClszz)
return this.mongoTemplate.findOne(query, returnClszz);
/**
* @description: 根据主键query查询返回
* @param
**/
public <T> List<T> findList(Query query,Class<T> returnClszz)
return this.mongoTemplate.find(query,returnClszz);
/**
* @description: 分页查询
* @param query mongo查询query
* @param returnClszz 查询返回对象
**/
public <T> PageListDTO<T> page(Query query,
Integer pageNum,
Integer pageSize,
Class<T> returnClszz)
if(pageNum != null && pageSize != null && pageSize > 0)
//设置起始数
query.skip((pageNum - 1) * pageSize);
//设置查询条数
query.limit(pageSize);
logger.info("mongo page param:", JSON.toJSONString(query));
List<T> list = this.mongoTemplate.find(query,returnClszz);
int count = count(query,returnClszz);
PageListDTO<T> pageList = new PageListDTO();
if(!CollectionUtils.isEmpty(list))
pageList.setData(list);
Pager pager = new Pager();
pager.setRecordCount(count);
pager.setCurrentPage(pageNum);
pager.setPageSize(pageSize);
if(pageSize != null && pageSize > 0)
pager.setTotalPage(count % pageSize == 0 ? 1 : count / pageSize + 1);
pageList.setPager(pager);
return pageList;
/**
* @description: 统计总条数
* @param query
* @param collectionClass
**/
public Integer count(Query query, Class<?> collectionClass)
logger.info("count param:",JSON.toJSONString(query));
return (int) this.mongoTemplate.count(query, collectionClass);
9:测试调用
@SpringBootTest
@RunWith(SpringRunner.class)
public class FailMqRecordApplicationTest
@Autowired
private GenericMongoQuery genericMongoQuery;
/**
* 按ID查询
*/
@Test
public MessageNoticePO getIdMessageNotice()
return this.genericMongoQuery.getOne(11, MessageNoticePO.class);
/**
* 按对象查询
*/
@Test
public MessageNoticePO queryMessageNotice()
Query query = new Query(); query.addCriteria(Criteria.where(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getMessageId)).is(messageId));
return this.genericMongoQuery.queryOne(query, MessageNoticePO.class);
/**
* 按传递的状态in + 名字查询
*/
@Test
public List<MessageNoticePO> queryMessageNoticeByQueueName(String queueName)
Query query = new Query();
ArrayList<Integer> states = new ArrayList<>();
states.add(1);
states.add(2);
query.addCriteria(Criteria.where(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getQueueName)).is(queueName) .and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getState)).in(states));
return this.genericMongoQuery.findList(query,MessageNoticePO.class);
/**
* 查询指定属性是null 并且状态是指定值的
*/
@Test
public List<MessageNoticePO> queryMessageNoticeList()
Query query = new Query();
Object obj = null;
Criteria criteria = new Criteria();
criteria.andOperator(new Criteria()
.andOperator( Criteria.where(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getMessageId)).in(obj), Criteria.where(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getRetryCount)).in(obj)));
criteria.and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getState)).is(1);
query.addCriteria(criteria);
return this.genericMongoQuery.findList(query,MessageNoticePO.class);
/**
* 分页查询
*/
@Test
public PageList<MessageNoticePO> queryMessageNoticePageList(MessageNoticeQuery recordQuery)
Query query = new Query();
Criteria criteria = new Criteria();
if(recordQuery.isMessageIdIsNotNull())
String messageId = ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getMessageId);
criteria.andOperator(
Criteria.where(messageId).exists(true),
Criteria.where(messageId).ne(true));
if(recordQuery.getState() != null)
criteria.and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getState)).is(recordQuery.getState());
if(recordQuery.getRequestType() != null)
criteria.and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getRequestType)).is(recordQuery.getRequestType());
if(StringUtils.isNotEmpty(recordQuery.getQueueName()))
Pattern pattern = Pattern.compile("^.*" + recordQuery.getQueueName() + ".*$", Pattern.CASE_INSENSITIVE);
criteria.and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getQueueName)).regex(pattern);
if(StringUtils.isNotEmpty(recordQuery.getRequestKey()))
Pattern pattern = Pattern.compile("^.*" + recordQuery.getRequestKey() + ".*$", Pattern.CASE_INSENSITIVE);
criteria.and(ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getRequestKey)).regex(pattern);
query.addCriteria(criteria);
if(recordQuery.isCreateTimeSort())
query.with(new Sort(Sort.Direction.DESC, ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getCreateTime)));
if(recordQuery.isUpdateTimeSort())
query.with(new Sort(Sort.Direction.DESC, ObjectParseUtils.getBeanFunName(MessageNoticeQuery::getLastUpdateTime)));
PageListDTO<MessageNoticePO> list = this.genericMongoQuery.page(query,
recordQuery.getPageNum(),
recordQuery.getPageSize(),
IFailMqRecordPO.class);
return 转换通用查询返回的分页数据给业务调用方(list);
10:新增改查都用的ObjectParseUtils 工具类
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
/**
* author : wb
* File Name: ObjectParseUtils
* Package Name: com.base.util
* Date: 2022/5/16 15:06
* Copyright (c) 2022,All Rights Reserved.
*/
public class ObjectParseUtils
/**
* @description: 解析主鍵
**/
public static String parsePrimaryKey(Object o)
try
Field[] fields = o.getClass().getDeclaredFields();
String primaryKey = "";
cas:for(Field fl:fields)
for(Annotation a :fl.getAnnotations())
if(a instanceof org.springframework.data.annotation.Id)
primaryKey += fl.getName();
break cas;
return primaryKey;
catch (Exception e)
throw new BusinessValidateException("数据操作失败");
/**
* @description: 解析对象的属性
* @param: o
* @return: list
**/
public static List<String> getFiledName(Object o)
try
Field[] fields = o.getClass().getDeclaredFields();
String[] fieldNames = new String[fields.length];
for (int i = 0; i < fields.length; i++)
fieldNames[i] = fields[i].getName();
return Arrays.asList(fieldNames);
catch (Exception e)
return new ArrayList<>();
/**
* @description: 解析对象属性对应的值
* @param: fieldNmae
* @param: o
* @return: object
**/
public static Object getFieldValueByName(String fieldName, Object o)
try
Method method = getFieldMethodByName(fieldName,o);
if(method == null)
throw new BusinessValidateException("操作异常");
return method.invoke(o, new Object[] );
catch (Exception e)
throw new BusinessValidateException("操作异常");
/**
* 返回方法体
*/
private static Method getFieldMethodByName(String fieldName, Object o)
try
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
return o.getClass().getMethod(getter, new Class[] );
catch (Exception e)
return null;
/**
* @description: 解析对象属性对应的值
* @param: fieldNmae
* @param: o
* @return: object
**/
public static Integer getFieldIntValueByName(String fieldName, Object o)
Integer num = null;
try
Method method = getFieldMethodByName(fieldName,o);
if(method != null)
num = (Integer)method.invoke(o, new Object[] );
catch (Exception e)
return num;
/**
* 根据匿名函数,获取bean 属性名称 <br>
* <li>BeanMapUtils.getBeanFunName(UserInfoDO::getCreateTime) = createTime</li>
* <li>BeanMapUtils.getBeanFunName(UserInfoDO::isOk) = ok</li>
*
* @date 2021-06-04 15:54
*/
public static <T> String getBeanFunName(Property<T, ?> property)
try
Method declaredMethod = property.getClass().getDeclaredMethod("writeReplace");
declaredMethod.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) declaredMethod.invoke(property);
String method = serializedLambda.getImplMethodName();
String attr;
if (method.startsWith("get"))
attr = (char) (method.charAt(3) + 32) + method.substring(4);
else if (method.startsWith("is"))
attr = (char) (method.charAt(2) + 32) + method.substring(3);
else
throw new IllegalStateException("无法处理的方法名" + method);
return attr;
catch (ReflectiveOperationException e)
throw new RuntimeException(e);
public interface Property<T, R> extends Function<T, R>, Serializable
11:查询入参对象
import java.io.Serializable;
import java.util.Date;
public class MessageRecordQuery implements Serializable
private String id;
private String userId;
private String queueName;
private Byte requestType;
private String requestKey;
private Byte state;
/**
* messageId 是否拼接Mongo $ne
*/
private boolean messageIdIsNotNull;
private boolean createTimeSort;
private boolean updateTimeSort;
private String messageId;
private Date lastUpdateTime;
private Date createTime;
private Integer retryCount;
/**
* 页码.
*/
private Integer pageNum;
/**
* 每页大小.
*/
private Integer pageSize;
/**
* 排序条件.
*/
private String orderBy;
//省略N set get
12:分页用到的 PageListDTO
import com.base.search.Pager;
import java.io.Serializable;
import java.util.List;
/**
* author : wb
* File Name: PageListDTO
* Package Name: com.base.dto.other
* Date: 2022/5/17 15:59
* Copyright (c) 2022,All Rights Reserved.
*/
public class PageListDTO<T> implements Serializable
public List<T> data;
public Pager pager;
public List<T> getData()
return data;
public void setData(List<T> data)
this.data = data;
public Pager getPager()
return pager;
public void setPager(Pager pager)
this.pager = pager;
13: 分页用到的Pager
/**
* 分页信息,主要用于查询返回的对象.
*
*/
public class Pager extends PagerCondition
/**
* serialVersionUID.
*/
private static final long serialVersionUID = 1L;
/**
* 总记录数
*/
private Integer recordCount;
/**
* 总页数
*/
private Integer totalPage;
public Pager()
super();
public Pager(Integer currentPage, Integer pageSize, Integer recordCount)
super(currentPage, pageSize);
this.recordCount = recordCount;
Integer totalPageSize = recordCount / pageSize;
Integer remailder = recordCount % pageSize;
// 如果总记录数与每页显示条数的余数大于0,总页数加1
if (remailder > 0)
totalPageSize = totalPageSize + 1;
totalPage = totalPageSize;
/**
* 分页查询时使用
*/
public Pager(PagerCondition pageCondition, Integer recordCount)
setCurrentPage(pageCondition.getCurrentPage());
setPageSize(pageCondition.getPageSize());
setRecordCount(recordCount);
setTotalPage((recordCount + getPageSize() - 1) / getPageSize());
public Integer getRecordCount()
return recordCount;
public void setRecordCount(Integer recordCount)
this.recordCount = recordCount;
public Integer getTotalPage()
return totalPage;
public void setTotalPage(Integer totalPage)
this.totalPage = totalPage;
以上是关于利用MongoTemplate 简单实现MongoDB 增删改查的主要内容,如果未能解决你的问题,请参考以下文章
利用MongoTemplate 简单实现MongoDB 增删改查
MongoDB Lifecycle 事件访问 MongoTemplate
MongoTemplate 排序不适用于 LocalDateTime
使用 mongoTemplate 在 spring-data-mongo Java 中进行 Mongo 聚合查询