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<String,Object> 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<String, Object> map,String tag,String city)
            throws Exception {

        kspositionrange=kspositionrange*kaoshengksposition/100;
        map.put("result", true);
        List<AggregationOperation> operations=new ArrayList<AggregationOperation>();
        //添加年份条件
        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<Map> raws=new ArrayList<Map>();
        int baoTotalPage=0;//bao总页数
        int wenTotalPage=0;//wen总页数
        int chongTotalPage=0;//chong总页数
        //控制显示字段


        if (baowenchong.toLowerCase().equals("bao")||isZYD==1) {
            //创建bao查询集合
            List<AggregationOperation> baoOperations=new ArrayList<AggregationOperation>();
            baoOperations.addAll(operations);
            baoOperations.add(Aggregation.match(
                    Criteria.where("fmaxksposition").gte(kaoshengksposition +kspositionrange)
            ));
            //获取总数
            List<AggregationOperation> countOperations=new ArrayList<AggregationOperation>();
            countOperations.addAll(baoOperations);
            int baoCount=getTotalCount(countOperations);
            count+=baoCount;
            baoTotalPage=(baoCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            baoOperations.add(getBaseShowFiled("bao"));
            List<Map> baoRaws=addPageInfoAndGetResult(baoOperations,currentPage,pageSize);
            raws.addAll(baoRaws);
        }
        if(baowenchong.toLowerCase().equals("wen")||isZYD==1){
            //创建wen查询集合
            List<AggregationOperation> wenOperations=new ArrayList<AggregationOperation>();
            wenOperations.addAll(operations);
            wenOperations.add(Aggregation.match(
                    Criteria.where("fmaxksposition").lte(kaoshengksposition-kspositionrange)
            ));
            wenOperations.add(Aggregation.match(
                    Criteria.where("fminksposition").gte(kaoshengksposition+kspositionrange)
            ));
            //获取总数
            List<AggregationOperation> countOperations=new ArrayList<AggregationOperation>();
            countOperations.addAll(wenOperations);
            int wenCount=getTotalCount(countOperations);
            count+=wenCount;
            wenTotalPage=(wenCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            CustomAggregationOperation projectOperation=getBaseShowFiled("wen");
            wenOperations.add(projectOperation);
            List<Map> wenRaws=addPageInfoAndGetResult(wenOperations,currentPage,pageSize);
            raws.addAll(wenRaws);
        }
        if(baowenchong.toLowerCase().equals("chong")||isZYD==1){
            //创建chong查询集合
            List<AggregationOperation> chongOperations=new ArrayList<AggregationOperation>();
            chongOperations.addAll(operations);
            chongOperations.add(Aggregation.match(
                    Criteria.where("fminksposition").lte(kaoshengksposition-kspositionrange)
            ));
            //获取总数
            List<AggregationOperation> countOperations=new ArrayList<AggregationOperation>();
            countOperations.addAll(chongOperations);
            int chongCount=getTotalCount(countOperations);
            count+=chongCount;
            chongTotalPage=(chongCount + pageSize  -1) / pageSize;
            //添加分页并获取结果集
            //获取要显示的字段
            chongOperations.add(getBaseShowFiled("chong"));
            List<Map> chongRaws=addPageInfoAndGetResult(chongOperations,currentPage,pageSize);
            raws.addAll(chongRaws);
        }
        Page page=new Page();
        page.setCurrentPage(currentPage);
        page.setPageSize(pageSize);
        //初始化数组
        List<Integer> totalPages = new ArrayList<Integer>();
        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<Map> addPageInfoAndGetResult(List<AggregationOperation> 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<Map> aggRes = mongoTemplate.aggregate(aggregation,
                "ptyxzslqtjb", Map.class);
        List<Map> raws=aggRes.getMappedResults();
        return raws;
    }

    /**
     * 获取总数
     * @param countOperations
     * @return
     */
    public int getTotalCount(List<AggregationOperation> countOperations){
        int count=0;
        countOperations.add(Aggregation.group().count().as("count"));
        Aggregation countaggregation =  Aggregation.newAggregation(countOperations);
        AggregationResults<Map> countRes = mongoTemplate.aggregate(countaggregation, "ptyxzslqtjb", Map.class);
        List<Map> 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: [ <value> , <value1> ... ]}

    

     

   例子:

     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. <span style="font-size:18px;">

  2. db. orders.insert([

  3. {

  4. "onumber" : "001",

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

  6. "cname" : "zcy1",

  7. "items" :[ {

  8. "ino" : "001",

  9. "quantity" :2,

  10. "price" : 4.0

  11. },{

  12. "ino" : "002",

  13. "quantity" : 4,

  14. "price" : 6.0

  15. }

  16. ]

  17. },{

  18. "onumber" : "002",

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

  20. "cname" : "zcy2",

  21. "items" :[ {

  22. "ino" : "001",

  23. "quantity" :2,

  24. "price" : 4.0

  25. },{

  26. "ino" : "002",

  27. "quantity" :6,

  28. "price" : 6.0

  29. }

  30. ]

  31. }

  32. ])</span>

 

 

 (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的文档,无关的文档没有返回,方便我们处理数据,这样也可以节省传输数据量,减少了内存消耗,提高了性能,在数据大时,性能很明显的。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在 Java 中使用 MongoDB 进行多表联查询可以通过使用 MongoDB 的聚合管道(Aggregation Pipeline)来实现。聚合管道是一系列操作步骤,可以将多个表的数据进行联和处理。 下面是一个示例代码,展示了如何在 Java 中使用 MongoDB 的聚合管道进行多表联查询: ```java import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.model.Aggregates; import com.mongodb.client.model.Filters; import com.mongodb.client.model.LookupOperation; import org.bson.Document; public class Main { public static void main(String[] args) { // 连接 MongoDB try (MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017")) { MongoCollection<Document> ordersCollection = mongoClient.getDatabase("mydb").getCollection("orders"); MongoCollection<Document> customersCollection = mongoClient.getDatabase("mydb").getCollection("customers"); // 定义聚合管道操作 LookupOperation lookupOperation = LookupOperation .from("customers", "customerId", "_id", "customerInfo"); // 构建聚合管道 AggregateIterable<Document> result = ordersCollection.aggregate(Arrays.asList( Aggregates.match(Filters.eq("status", "completed")), lookupOperation )); // 遍历查询结果 for (Document document : result) { System.out.println(document); } } } } ``` 上述示例代码中,我们假设有两个集合:`orders` 和 `customers`。`orders` 集合中的每个文档包含一个 `customerId` 字段,该字段与 `customers` 集合中的 `_id` 字段联。我们使用 `LookupOperation` 来进行联查询,并使用 `match` 操作来过滤出状态为 "completed" 的订单。 请注意,这只是一个简单的示例,实际的多表联查询可能需要更复杂的聚合管道操作来满足特定的需求。你可以根据自己的实际情况进行相应的调整和扩展。 希望能帮助到你!如果有更多问题,请随时提问。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值