Spring Data MongoDB 五:进阶文档查询(分页Morphia)

Posted jhcelue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 设置返回须要的字段

     技术分享

 

      MongoDBserver返回的查询结果, 当调用cursor.hasNext()时。MongoDB批量的大小不会超过最大BSON文档大小,然而对于大多数查询,第一批返回101文档或足够的文件超过1 MB,兴许的批大小为4 MB。假设第一批是返回101个文档时,遍历完时,运行hasNext,会到数据库查询结果。直到全部结果都被返回,游标才会结关闭。

 


 

四.其它的查询方法

     mongoTemplate .findAll   查询集合全部的文档 相当于MongoDB的db.collect.find()。

     mongoTemplate .findById  依据文档_ID查询相应的文档。

     mongoTemplate .findAndRemove  依据查询条件。查询匹配的文档返回。并从数据库中删除。


     我们在查询时,这边默认是有使用到索引,对于数据量大的文档,须要建立合适的索引。加快查询效率。

















以上是关于Spring Data MongoDB 五:进阶文档查询(分页Morphia)的主要内容,如果未能解决你的问题,请参考以下文章

如何利用spring data mongodb 进行多条件查询

@Tailable(spring-data-reactive-mongodb) 等效于 spring-data-r2dbc

Spring -Data MongoDB问题与作为接口的字段

用Spring data查询mongodb的问题,求解答

使用Spring访问Mongodb的方法大全——Spring Data MongoDB

如何在 spring-boot 中禁用 spring-data-mongodb 自动配置