在Java中除了使用源生的方式操作MongoDB,还可以使用MongoTemplate封装类。
首先pom中引入依赖
org.springframework.data
spring-data-mongodb
大多数情况下,还是使用实体类的方式来封装mongoDB的document,以此来实现一一对应。
@Component
@Document(collection="user")
@Data
public class User{
private String id;//主键
private String userName;//用户名
private String createBy;//创建人
private Date createTm;//创建时间
private String modifyBy;//修改人
private Date modifyTm;//修改时间
}
这里要说明一下,MongoDB的主键是_id,在定义实体类时,可以使用id,方便操作,会自动与数据库对应的。
其中@Document注解是用来指定数据库的collection,这样就知道该去操作哪个collection了。
@Data使用了lombok来自动生成getter、setter、constructor、toString等方法,需要引入依赖
org.projectlombok
lombok
false
下面介绍最基本的CRUD
新增
public void saveUser(User user) {
mongoTemplate.save(user);
}
在实体类中set好相应的字段,直接调用save方法,调用完成后,user中的id字段会被自动填值,可以取得主键。
查询
Query query = new Query(Criteria.where("userName").is(username));
List users = mongoTemplate.find(query, User.class);
先new一个Query,在构造方法中可以传一个Criteria,作为类似mysql的where语句,可以在后面用.and继续连接。
查询可以使用排序和分页
query.with(Sort.by(Sort.Order.desc("name")));
query.skip(0);
query.limit(1);
这里的with就是指定一个排序策略,skip就是从第几条开始,limit就是一共查多少条
修改
public void updateUser(User user) {
Field[] fields=User.class.getDeclaredFields();
Update update = new Update();
for(Field field : fields) {
field.setAccessible(true);
Object val=null;
try {
val = field.get(user);
} catch (IllegalArgumentException e) {
e.getMessage();
} catch (IllegalAccessException e) {
e.getMessage();
}
String key = field.getName();
if(val!=null&&!"id".equals(key)) {
update.set(key, val);
}
}
Query query = new Query(Criteria.where("id").is(user.getId()));
mongoTemplate.updateFirst(query, update, User.class);
}
这里用到了反射的方法来构造Update对象,也可以要修改哪一列就用update.set(key,val)的方式显式地写
删除
public void deleteUser(String id) {
Query query = new Query(Criteria.where("id").is(id));
mongoTemplate.remove(query, User.class);
}
删除一样是用Query对象来声明条件,删除符合条件的document。
下面重点介绍一下复杂查询,会用到Aggregate聚合查询。
假设这样一个场景,MongoDB中存的json字符串含有一个数组,如
{
"name":"小明",
"no":"20180105",
"test":[
{"subject":"数学",
"result":98
},{"subject":"语文",
"result":80
},{"subject":"英语",
"result":91
}
]
},
{
"name":"小丽",
"no":"20180106",
"test":[
{"subject":"数学",
"result":92
},{"subject":"语文",
"result":95
},{"subject":"英语",
"result":93
}
]
}
这里存放的是学生的考试信息,包含姓名、学号和考试成绩,其中考试成绩是一个对象数组,包含了不同学科的考试成绩。
如果想只查询所有学生的数学成绩,用普通的查询方法,会把其他成绩也带出来,如果把数组拆开呢,这里就要使用聚合查询加上$unwind关键字。
Criteria condition = Criteria.where("test.subject").is("数学");
Aggregation aggregationQuery = Aggregation.newAggregation(Aggregation.unwind("test"),
Aggregation.match(condition),
Aggregation.sort(Sort.by(Sort.Order.desc("test.result"))),
Aggregation.skip((pageNo.longValue()-1L)*pageSize.longValue()),
Aggregation.limit(pageSize.longValue()));
@SuppressWarnings("rawtypes")
List
这样就可以查到每个学生的数学成绩,按照成绩倒序排序,并且使用分页。注意,这里查出来的是个Map,并不是实体类。
关于其他的关键字,网上搜索有一大堆,这里就不赘述了。
如果result成绩是用String来存储的,这时候排序字符串可能就会有问题,那该怎么解决呢
可以使用
aggregationQuery = aggregationQuery.withOptions(
new AggregationOptions.Builder()
.collation(Collation.of(new Locale("zh")).
numericOrderingEnabled()).build());
按照字符串数字来进行排序,并指定了是中文。