mongodb关联表查询

1.首先自定义一个查询的Operation

package com.pica.wx.bean;

import com.mongodb.DBObject;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;

/**
 * @author lqx
 * @create 2018-09-01 10:41
 */

public class CustomAggregationOperation  implements AggregationOperation {

    private DBObject operation;

    public CustomAggregationOperation (DBObject operation) {
        this.operation = operation;
    }


    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }


}

 

关联表查询如下

/**
     * 获取表单数据
     * @param isZYD 是不是志愿单页面0不是1是
     * @param ksmc
     * @param year
     * @param kaoshengksposition
     * @param kspositionrange
     * @param baowenchong
     * @param cbatch
     * @param yxdm
     * @param yxmc
     * @param currentPage
     * @param pageSize
     * @param sort_column
     * @param sort_direction
     * @param map
     * @param tag
     * @param city
     * @return
     * @throws Exception
     */
    public Map findSchoolBWC(Integer isZYD,String ksmc, int year, int kaoshengksposition, int kspositionrange, String baowenchong, String cbatch,
                                            String yxdm, String yxmc, int currentPage, int pageSize, String sort_column, String sort_direction, Map map,String tag,String city)
            throws Exception {

        kspositionrange=kspositionrange*kaoshengksposition/100;
        map.put("result", true);
        List operations=new ArrayList();
        //添加年份条件
        operations.add(Aggregation.match(Criteria.where("year").is(year)));
        //关联school表获取city和tag
        operations.add(new CustomAggregationOperation(
                new BasicDBObject(
                        "$lookup",
                        new BasicDBObject("from", "schools")
                                .append("localField","yxmc")
                                .append("foreignField", "name")
                                .append("as", "schools")
                )
        ));
        //添加批次条件
        operations.add(Aggregation.match(
                Criteria.where("cbatch").is(cbatch)
        ));
        //添加科目条件
        operations.add(Aggregation.match(
                Criteria.where("ksmc").is(ksmc)
        ));
        //添加排序
        operations.add(Aggregation.sort(
                new Sort(new Sort.Order(sort_direction.toLowerCase().equals("desc") ? Direction.DESC:Direction.ASC,sort_column))
        ));
        //添加城市条件
        if(StringUtils.isNotBlank(city)){
            operations.add(Aggregation.match(
                    Criteria.where("schools.cityname").is(city)
            ));
        }
        //添加tag条件
        if(StringUtils.isNotBlank(tag)){
            operations.add(Aggregation.match(
                    Criteria.where("schools.tags").regex(tag)
            ));
        }
        int count=0;//总数
        List raws=new ArrayList();
        int baoTotalPage=0;//bao总页数
        int wenTotalPage=0;//wen总页数
        int chongTotalPage=0;//chong总页数
        //控制显示字段


        if (baowenchong.toLowerCase().equals("bao")||isZYD==1) {
            //创建bao查询集合
            List baoOperations=new ArrayList();
            baoOperations.addAll(operations);
            baoOperations.add(Aggregation.match(
                    Criteria.where("fmaxksposition").gte(kaoshengksposition +kspositionrange)
            ));
            //获取总数
            List countOperations=new ArrayList();
            countOperations.addAll(baoOperations);
            int baoCount=getTotalCount(countOperations);
            count+=baoCount;
            baoTotalPage=(baoCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            baoOperations.add(getBaseShowFiled("bao"));
            List baoRaws=addPageInfoAndGetResult(baoOperations,currentPage,pageSize);
            raws.addAll(baoRaws);
        }
        if(baowenchong.toLowerCase().equals("wen")||isZYD==1){
            //创建wen查询集合
            List wenOperations=new ArrayList();
            wenOperations.addAll(operations);
            wenOperations.add(Aggregation.match(
                    Criteria.where("fmaxksposition").lte(kaoshengksposition-kspositionrange)
            ));
            wenOperations.add(Aggregation.match(
                    Criteria.where("fminksposition").gte(kaoshengksposition+kspositionrange)
            ));
            //获取总数
            List countOperations=new ArrayList();
            countOperations.addAll(wenOperations);
            int wenCount=getTotalCount(countOperations);
            count+=wenCount;
            wenTotalPage=(wenCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            CustomAggregationOperation projectOperation=getBaseShowFiled("wen");
            wenOperations.add(projectOperation);
            List wenRaws=addPageInfoAndGetResult(wenOperations,currentPage,pageSize);
            raws.addAll(wenRaws);
        }
        if(baowenchong.toLowerCase().equals("chong")||isZYD==1){
            //创建chong查询集合
            List chongOperations=new ArrayList();
            chongOperations.addAll(operations);
            chongOperations.add(Aggregation.match(
                    Criteria.where("fminksposition").lte(kaoshengksposition-kspositionrange)
            ));
            //获取总数
            List countOperations=new ArrayList();
            countOperations.addAll(chongOperations);
            int chongCount=getTotalCount(countOperations);
            count+=chongCount;
            chongTotalPage=(chongCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            chongOperations.add(getBaseShowFiled("chong"));
            List chongRaws=addPageInfoAndGetResult(chongOperations,currentPage,pageSize);
            raws.addAll(chongRaws);
        }
        Page page=new Page();
        page.setCurrentPage(currentPage);
        page.setPageSize(pageSize);
        //初始化数组
        List totalPages = new ArrayList();
        totalPages.add(baoTotalPage);
        totalPages.add(wenTotalPage);
        totalPages.add(chongTotalPage);
        //获取最大页数作为总页数
        page.setTotalPage(Collections.max(totalPages));
        page.setRows(raws);
        page.setTotalCount(count);
        map.put("data", page);
        //获取往年情况
        if(page.getRows()!=null&&page.getRows().size()>0){
            chanWangNianLQQK(map,page,ksmc,year,cbatch,kaoshengksposition);
        }
        return map;
    }

3.如果要添加自定义字段,上面方法中用到的方法如下

 /**
     * 获取要显示的字段
     * @param baowenchong
     * @return
     */
    public CustomAggregationOperation getBaseShowFiled(String baowenchong){
        CustomAggregationOperation projectOperation=new CustomAggregationOperation(
                new BasicDBObject(
                        "$project",
                        new BasicDBObject("year", 1)
                                .append("yxmc",1)
                                .append("ksmcname", 1)
                                .append("cbatch", 1)
                                .append("cbatchname", 1)
                                .append("yxdm", 1)
                                .append("yxmc", 1)
                                .append("plan", 1)
                                .append("planenrollment", 1)
                                .append("enrollment", 1)
                                .append("fmax", 1)
                                .append("fmin", 1)
                                .append("favg", 1)
                                .append("fmaxksposition", 1)
                                .append("fminksposition", 1)
                                .append("yxsf", 1)
                                .append("yxtag", 1)
                                .append("schools", 1)
                                .append("baowenchong", baowenchong)
                )
        );
        return projectOperation;
    }
    /**
     * 添加分页并获取结果集
     * @param operations
     * @param currentPage
     * @param pageSize
     * @return
     */
    public List addPageInfoAndGetResult(List operations,Integer currentPage,Integer pageSize){
        operations.add(Aggregation.skip((long)((currentPage-1)*pageSize)));
        operations.add(Aggregation.limit((long)pageSize));

        Aggregation aggregation =  Aggregation.newAggregation(operations);
        AggregationResults aggRes = mongoTemplate.aggregate(aggregation,
                "ptyxzslqtjb", Map.class);
        List raws=aggRes.getMappedResults();
        return raws;
    }

    /**
     * 获取总数
     * @param countOperations
     * @return
     */
    public int getTotalCount(List countOperations){
        int count=0;
        countOperations.add(Aggregation.group().count().as("count"));
        Aggregation countaggregation =  Aggregation.newAggregation(countOperations);
        AggregationResults countRes = mongoTemplate.aggregate(countaggregation, "ptyxzslqtjb", Map.class);
        List coutMapRes = countRes.getMappedResults();
        if(coutMapRes!=null&&coutMapRes.size()>0){
            count =  (Integer)coutMapRes.get(0).get("count");
        }
        return count;
    }

4.数组查询方法

对数组根据条件查询

 

   $all、$size、$slice、$elemMatch

  

(1)$all查找数组中包含指定的值的文档

     语法:

        { field:{ $all: [ , ... ]}

    

     

   例子:

     db.orders.find({"books":{$all:["java","mongo"]}})

   

      

    

     查找books包含java、mongo的文档数据

 

(2)$size 查找数组大小等于指定值的文档

     语法:

        

   {field: {$size: number } }

 

 

      例子:

        

          >db.orders.find({"books":{$size:2}})

 

 

       

 

(3)$slice查询数组中指定返回元素的个数

      语法:

         

         >db.collect.find({},{field:{$slice: number }})

 

 

 

      number 说明:

         为正数表示返回前面指定的值的个数:例如1 返回数组第一个

         为负数表示返回倒数指定的值的个数:例如-1返回数组倒数第一个

 

      例子:

            

        >db.orders.find({"onumber":{$in:["008","009"]}},{books:{$slice:1}})

 

 

          

 

 

    1)$slice可以查询数组中第几个到第几个

    

        语法:

           

            >db.collect.find({},{field:{$slice:[ number1, number2] }})

 

 

       跳过数组的number1个位置然后返回number2个数

       number1说明:

          为正数表示跳到指定值的数组个数:例如2 跳到数组第3个

          为负数表示跳到指定值的数组倒数个数:例如-2跳到到数组倒数第3个

 

       例子:

          

           >db.orders.find({"onumber":{$in:["008","009"]}},{books:{$slice:[1,1]}})

 

 

         

 

         跳过books数组第一个元素,现在到数组第二个元素,并返回1个元素

 

 

三、对数组内嵌文档查询

      我们先保存数据

 
  1. db. orders.insert([

  2. {

  3. "onumber" : "001",

  4. "date" : "2015-07-02",

  5. "cname" : "zcy1",

  6. "items" :[ {

  7. "ino" : "001",

  8. "quantity" :2,

  9. "price" : 4.0

  10. },{

  11. "ino" : "002",

  12. "quantity" : 4,

  13. "price" : 6.0

  14. }

  15. ]

  16. },{

  17. "onumber" : "002",

  18. "date" : "2015-07-02",

  19. "cname" : "zcy2",

  20. "items" :[ {

  21. "ino" : "001",

  22. "quantity" :2,

  23. "price" : 4.0

  24. },{

  25. "ino" : "002",

  26. "quantity" :6,

  27. "price" : 6.0

  28. }

  29. ]

  30. }

  31. ])

 

 

 (1)$elemMatch 文档包含有一个元素是数组,那么$elemMatch可以匹配内数组内的元素并返回文档数据

     语法:

        

 

         >{field:{$elemMatch:{ field1:value1, field2:value2,………}}}

 

 

   例子:

       

         >db.orders.find({"items":{$elemMatch:{"quantity":2}}})

 

 

      

      返回quantity为2的文档

 

   也可以这样查询db.orders.find({"items.quantity":2})

      

 

(2) $elemMatch可以带多个查询条件

   

   例子:

        

      >db.orders.find({"items":{$elemMatch:{"quantity":4,"ino":"002"}}})

 

 

      

 

      我们查询数组中的quantity等于4并且ino等于002,但是我们就想返回数组中的quantity等于4并且ino等于002的这个文档,并不想把ino等于001等这些无关的文档返回。

 

 

(3)$elemMatch 同样可以用在find方法的第二个参数来限制返回数组内的元素,只返回我们需要的文档

   

   例子:

         db.orders.find({"onumber":"001"},{"items":{$elemMatch:{"quantity":4,"ino":"002"}},"cname":1,"date":1,"onumber":1})

         

         

       

 我们只返回quantity等于4并且ino等于002的文档,无关的文档没有返回,方便我们处理数据,这样也可以节省传输数据量,减少了内存消耗,提高了性能,在数据大时,性能很明显的。

你可能感兴趣的:(java)