Spring Data MongoDB 五:进阶文档查询(分页、Morphia)(二)
Spring Data MongoDB 三:基本文档查询(Query、BasicQuery)(一)
学习MongoDB 六: MongoDB查询(游标操作、游标信息)(三)
一.简介
SpringData MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的find的操作,我们上一篇介绍了基本文档的查询,我们今天介绍分页查询,分页查询是返回到匹配文档的游标,可以随意修改查询限制、跳跃、和排序顺序的功能。
我们在查询时find()方法接受Query类型有org.springframework.data.mongodb.core.query和org.springframework.data.mongodb.core.query.BasicQuery
Query类提供方法有limit、skip、sort查询限制、跳跃、和排序顺序的功能,BasicQuery继承了Query类。
Query |
Mongodb |
说明 |
Query limit (int limit) |
limit |
方法是限制游标返回结果的数量 |
Query skip (int skip) |
skip |
方法可以跳过指定值的条数,返回剩下的条数的结果,可以跟limit()方法进行组合可以实现分页的效果 |
Sort sort () 已过时 现在是用query.with(sort) |
sort |
方法来对数据进行排序,根据指定的字段,并使用1或-1来指定排序方式是升序或降序,类似于SQL的order by。 |
二.基本分页
Query类提供方法有limit、skip、sort查询限制、跳跃、和排序顺序的功能,我们实现Query查询分页
第一步:实现分页工具类
/** * 分页 * @author zhengcy * * @param<T> */ public classPageModel<T>{ //结果集 privateList<T> datas; //查询记录数 privateintrowCount; //每页多少条数据 privateintpageSize=20; //第几页 privateintpageNo=1; //跳过几条数 privateintskip=0; /** * 总页数 * @return */ publicintgetTotalPages(){ return(rowCount+pageSize-1)/pageSize; } public List<T>getDatas() { return datas; } public void setDatas(List<T>datas) { this.datas = datas; } public int getRowCount() { return rowCount; } public void setRowCount(int rowCount) { this.rowCount = rowCount; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getSkip() { skip=(pageNo-1)*pageSize; return skip; } public void setSkip(int skip) { this.skip = skip; } public int getPageNo() { return pageNo; } public void setPageNo(int pageNo) { this.pageNo = pageNo; } }
第二步:实现分页
@Override public PageModel<Orders>getOrders(PageModel<Orders> page, DBObject queryObject,StringcollectionName) { Queryquery=newBasicQuery(queryObject); //查询总数 int count=(int) mongoTemplate.count(query,Orders.class); page.setRowCount(count); //排序 query.with(new Sort(Direction.ASC, "onumber")); query.skip(page.getSkip()).limit(page.getPageSize()); List<Orders>datas=mongoTemplate.find(query,Orders.class); page.setDatas(datas); return page; }
说明:
Sort :sort () 已过时,现在是用query.with(sort),with参数是sort类
Sort提供了几种构造函数
方法的描述
(1)一个字段的排序
例如onumber字段升序
query.with(new Sort(Direction.ASC,"onumber"));
(2)如果是多个字段时同时升序或者降序时
//排序
query.with(new Sort(Direction.ASC,"a","b","c"));
(3)不同的字段按照不同的排序
List<Sort.Order>orders=new ArrayList<Sort.Order>(); orders.add(newSort.Order(Direction.ASC, "a")); orders.add(newSort.Order(Direction.DESC, "b")); query.with(newSort(orders ));
a升序在按b降序
第三步:测试类
@Test public void testList() throws ParseException { PageModel<Orders>page=newPageModel<Orders>(); page.setPageNo(1); page=ordersDao.getOrders(page, new BasicDBObject("cname","zcy"),collectionName); System.out.println("总数:"+page.getRowCount()); System.out.println("返回条数:"+page.getDatas().size()); System.out.println(JSONArray.fromObject(page.getDatas())); }
查询条件是cname=zcy
skip方法是跳过条数,而且是一条一条的跳过,如果集合比较大时(如书页数很多)skip会越来越慢, 需要更多的处理器(CPU),这会影响性能。
三、进阶的查询分页
返回到匹配文档的游标,可以随意修改查询限制、跳跃、和排序顺序的功能,我们这边对指针返回的结果,我用到Morphia框架。
Morphia是一个开放源代码的对象关系映射框架,它对MongoDB数据库 java版驱动进行了非常轻量级的对象封装。我们需要通过DBCurosr获取的DBObject转换成我们对应的实体对象,方便我们操作实体。
DBCurosr 是 DBCollection 的 find 方法返回的对象,可以设置 skip、limit 、sot等属性执行分页查询
第一步:在实体id要注解@id
importcom.google.code.morphia.annotations.Id;
@Id
privateString id;
@Id 注释指示Morphia哪个字段用作文档 ID
如果没加的话,会出现这样的错误
...27 more
Caused by: com.google.code.morphia.mapping.validation.ConstraintViolationException: Number of violations: 1
NoId complained aboutcom.mongo.model.Orders. : No field is annotated with @Id; but it is required
atcom.google.code.morphia.mapping.validation.MappingValidator.validate(MappingValidator.java:66)
atcom.google.code.morphia.mapping.validation.MappingValidator.validate(MappingValidator.java:155)
atcom.google.code.morphia.mapping.MappedClass.validate(MappedClass.java:259)
atcom.google.code.morphia.mapping.Mapper.addMappedClass(Mapper.java:154)
atcom.google.code.morphia.mapping.Mapper.addMappedClass(Mapper.java:142)
atcom.google.code.morphia.Morphia.map(Morphia.java:55)
atcom.mongo.dao.impl.OrdersDaoImpl.<init>(OrdersDaoImpl.java:37)
atsun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
atsun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
atsun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
atjava.lang.reflect.Constructor.newInstance(Unknown Source)
atorg.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 29more
第二步:实现:
privateMorphia morphia; public OrdersDaoImpl(){ morphia= new Morphia(); morphia.map(Orders.class); } @Override public PageModel<Orders>getOrders(PageModel<Orders> page, DBObject queryObject,StringcollectionName) { DBObjectfilterDBObject=newBasicDBObject(); filterDBObject.put("_id", 0); filterDBObject.put("cname",1); filterDBObject.put("onumber",1); DBCursordbCursor=mongoTemplate.getCollection(collectionName).find(queryObject,filterDBObject); //排序 DBObjectsortDBObject=newBasicDBObject(); sortDBObject.put("onumber",1); dbCursor.sort(sortDBObject); //分页查询 dbCursor.skip(page.getSkip()).limit(page.getPageSize()); //总数 int count=dbCursor.count(); //循环指针 List<Orders>datas=newArrayList<Orders>(); while (dbCursor.hasNext()) { datas.add(morphia.fromDBObject(Orders.class, dbCursor.next())); } page.setRowCount(count); page.setDatas(datas); return page; }
我们开始执行DAO时,先初始化Morphia,并往里面添加我们需要转换的实体类CLASS
morphia=new Morphia();
morphia.map(Orders.class);
dbCursor.hasNext()判断是否还有下一个文档(DBObject), dbCursor.Next()获取DBObject时,我们通过Morphia把DBObject对应的实体类。
查询时通过filterDBObject 设置返回需要的字段
MongoDB服务器返回的查询结果, 当调用cursor.hasNext()时,MongoDB批量的大小不会超过最大BSON文档大小,然而对于大多数查询,第一批返回101文档或足够的文件超过1 MB,后续的批大小为4 MB。如果第一批是返回101个文档时,遍历完时,执行hasNext,会到数据库查询结果,直到所有结果都被返回,游标才会结关闭。
四.其他的查询方法
mongoTemplate .findAll 查询集合所有的文档 相当于MongoDB的db.collect.find()。
mongoTemplate .findById 根据文档_ID查询对应的文档。
mongoTemplate .findAndRemove 根据查询条件,查询匹配的文档返回,并从数据库中删除。
我们在查询时,这边默认是有使用到索引,对于数据量大的文档,需要建立合适的索引,加快查询效率。
版权声明:本文为博主原创文章,未经博主允许不得转载。