MongoDB的一些基本操作
MongoDB配置,CRUD操作,条件查询
简单记录一下自己使用的MongoDB的一些操作。
配置
处理了_class的不必要的生成,自定义一个递增的注解:
//mongodb中生成的记录忽略_class字段
@Configuration
public class MongoConfig {
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context,
BeanFactory beanFactory) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
try {
mappingConverter.setCustomConversions(beanFactory.getBean(CustomConversions.class));
} catch (NoSuchBeanDefinitionException ignore) {
}
// Don't save _class to mongo
mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
return mappingConverter;
}
}
自定义递增注解,mongodb无法设置字段自动递增,mongodb数据类型是一些基本数据类型,如果字段不设置int,long类型无法实现自动注解的功能。通过监听mongodb的生命周期事件,然后进行重写实现。
@Component
public class MongoDBEventListener extends AbstractMongoEventListener<Object> {
@SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(MongoDBEventListener.class);
@Autowired
private MongoTemplate mongoTemplate;
/**
* 在新增记录的时候,回调接口方法,监听文档插入记录的操作,使用反射方法对ID进行自增
*
* @param event
* @since 1.8
*/
@Override
public void onBeforeConvert(BeforeConvertEvent<Object> event) {
final Object source = event.getSource(); // 获取事件最初发生的对象
if (source != null) {
// 使用反射工具类,实现回调接口的方法,对成员进行操作
ReflectionUtils.doWithFields(source.getClass(), new FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
ReflectionUtils.makeAccessible(field); // 使操作的成员可访问
// 如果是带有@AutoIncrement注解的,成员调用getter方法返回的类型是Number类型的,返回的类型都是0的(没有赋值,默认为0)
if (field.isAnnotationPresent(AutoIncrement.class) && field.get(source) instanceof Number
&& field.getLong(source) == 0) {
String collName = source.getClass().getSimpleName().substring(0, 1).toLowerCase()
+ source.getClass().getSimpleName().substring(1);
// setter方法的调用,使ID成员属性,进行自增
field.set(source, getNextId(collName));
}
}
});
}
}
/**
* 返回下一个自增的ID
*
* @param collName
* 集合名称(一般规则是,类名的第一个字母小写,然后按照驼峰书写法)
* @return Long 序列值
*/
private Long getNextId(String collName) {
Query query = new Query(Criteria.where("collName").is(collName));
List<SequenceId> list = mongoTemplate.find(query, SequenceId.class);
SequenceId seq = null;
Date now = new Date();
if(list.size() > 0){
Update update = new Update();
update.inc("seqId", 1).set("gmtUpdate",now);
FindAndModifyOptions options = new FindAndModifyOptions();
options.upsert(true);
options.returnNew(true);
seq = mongoTemplate.findAndModify(query, update, options, SequenceId.class);
return seq.getSeqId();
}else{
seq = new SequenceId();
seq.setCollName(collName);
seq.setGmtCreate(now);
seq.setIsDelete("0");
seq.setSeqId((long) 1);
mongoTemplate.save(seq);
return seq.getSeqId();
}
}
/**
* Captures {@link BeforeSaveEvent}.
*
* @param event will never be {@literal null}.
* @since 1.8
*/
@Override
public void onBeforeSave(BeforeSaveEvent<Object> event) {
//super.onBeforeSave(event);
}
/**
* Captures {@link AfterSaveEvent}.
*
* @param event will never be {@literal null}.
* @since 1.8
*/
@Override
public void onAfterSave(AfterSaveEvent<Object> event) {
//super.onAfterSave(event);
}
/**
* 过滤掉isDelete=1 的数据
*
*/
@Override
public void onAfterLoad(AfterLoadEvent<Object> event) {
//super.onAfterLoad(event);
}
/**
* Captures {@link AfterConvertEvent}.
*
* @param event will never be {@literal null}.
* @since 1.8
*/
@Override
public void onAfterConvert(AfterConvertEvent<Object> event) {
//super.onAfterConvert(event);
}
/**
* Captures {@link AfterDeleteEvent}.
*
* @param event will never be {@literal null}.
* @since 1.8
*/
@Override
public void onAfterDelete(AfterDeleteEvent<Object> event) {
//super.onAfterDelete(event);
}
/**
* Capture {@link BeforeDeleteEvent}.
*
* @param event will never be {@literal null}.
* @since 1.8
*/
@Override
public void onBeforeDelete(BeforeDeleteEvent<Object> event) {
//super.onBeforeDelete(event);
}
}
CRUD操作
简单的CRUD操作可以继承MongoRepository。也可以注入MongoTemplate 或者是MongoOperations进行一些操作,这两个类里面封装了很多原生的方法。
条件查询
- 继承MongoRepository
@Override
<S extends T> List<S> findAll(Example<S> example);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
*/
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
Example 的使用利用一个对象设置字段值,
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.domain;
import org.springframework.util.ClassUtils;
/**
* Support for query by example (QBE). An {@link Example} takes a {@code probe} to define the example. Matching options
* and type safety can be tuned using {@link ExampleMatcher}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @author Oliver Gierke
* @param <T> the type of the probe.
* @since 1.12
*/
public interface Example<T> {
/**
* Create a new {@link Example} including all non-null properties by default.
*
* @param probe must not be {@literal null}.
* @return
*/
static <T> Example<T> of(T probe) {
return new TypedExample<>(probe, ExampleMatcher.matching());
}
/**
* Create a new {@link Example} using the given {@link ExampleMatcher}.
*
* @param probe must not be {@literal null}.
* @param matcher must not be {@literal null}.
* @return
*/
static <T> Example<T> of(T probe, ExampleMatcher matcher) {
return new TypedExample<>(probe, matcher);
}
/**
* Get the example used.
*
* @return never {@literal null}.
*/
T getProbe();
/**
* Get the {@link ExampleMatcher} used.
*
* @return never {@literal null}.
*/
ExampleMatcher getMatcher();
/**
* Get the actual type for the probe used. This is usually the given class, but the original class in case of a
* CGLIB-generated subclass.
*
* @return
* @see ClassUtils#getUserClass(Class)
*/
@SuppressWarnings("unchecked")
default Class<T> getProbeType() {
return (Class<T>) ClassUtils.getUserClass(getProbe().getClass());
}
}
利用ExampleMatcher matcher可以设置一些条件
可以参考
https://blog.youkuaiyun.com/moshowgame/article/details/80282813
- 另外的一种条件拼接采用MongoTemplate 的方法
@Override
public List<RecordApi> findByPage(RecordApiForm form, Pageable pageable) {
Query query = new Query();
if (StringUtils.isNotBlank(form.getChannel())) {
query.addCriteria(Criteria.where("channel").regex("^.*" + form.getChannel() + ".*$"));
}
if (StringUtils.isNotBlank(form.getBusiness())) {
query.addCriteria(Criteria.where("business").regex("^.*" + form.getBusiness() + ".*$"));
}
if (StringUtils.isNotBlank(form.getMethod())) {
query.addCriteria(Criteria.where("method").regex("^.*" + form.getMethod() + ".*$"));
}
if (isEmpty(form.getStart_time()) && isEmpty(form.getEnd_time())) {
query.addCriteria(Criteria.where("gmtCreate").gte(form.getStart_time()).lte(form.getEnd_time()));
} else if (isEmpty(form.getStart_time())) {
query.addCriteria(Criteria.where("gmtCreate").gte(form.getStart_time()));
} else if (isEmpty(form.getEnd_time())) {
query.addCriteria(Criteria.where("gmtCreate").lte(form.getEnd_time()));
}
if (isEmpty(pageable)) {
query.with(pageable);
}
return mongoTemplate.find(query, RecordApi.class);
}