zoukankan      html  css  js  c++  java
  • MongoDB数据库GroupBy查询使用Spring-data-mongondb的实现

    以前用MongoDB数据库都是简单的查询,直接用Query就可以,最近项目中用到了分组查询,完全不一样。第一次遇到,搞了好几天终于有点那意思了。

    先上代码:

      1 import java.math.BigDecimal;
      2 import java.text.ParseException;
      3 import java.text.SimpleDateFormat;
      4 import java.util.ArrayList;
      5 import java.util.Date;
      6 import java.util.List;
      7 
      8 import org.slf4j.Logger;
      9 import org.slf4j.LoggerFactory;
     10 import org.springframework.beans.factory.annotation.Autowired;
     11 import org.springframework.data.mongodb.core.MongoTemplate;
     12 import org.springframework.data.mongodb.core.aggregation.Aggregation;
     13 import org.springframework.data.mongodb.core.aggregation.AggregationResults;
     14 import org.springframework.data.mongodb.core.aggregation.Fields;
     15 import org.springframework.data.mongodb.core.aggregation.GroupOperation;
     16 import org.springframework.data.mongodb.core.aggregation.MatchOperation;
     17 import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
     18 import org.springframework.data.mongodb.core.mapreduce.GroupBy;
     19 import org.springframework.data.mongodb.core.mapreduce.GroupByResults;
     20 import org.springframework.data.mongodb.core.query.Criteria;
     21 import org.springframework.stereotype.Service;
     22 
     23 import com.mongodb.BasicDBList;
     24 import com.mongodb.BasicDBObject;
     25 import com.mongodb.CommandResult;
     26 
     27 @Service
     28 public class EquipmentRepository implements EquipmentRepository{
     29 
     30     private static final Logger logger = LoggerFactory.getLogger(EquipmentRepository.class);
     31     
     32     @Autowired
     33     MongoTemplate mongoTemplate;
     34 
     35     
     36     
     37     /**
     38      *<p>从登陆信息表中根据IP统计设备使用时间</p>
     39      * @param hostName 设备名称
     40      * @param startTime 统计开始时间
     41      * @param endTime 统计结束时间
     42      * @return 统计信息
     43      */    
     44     @Override
     45     public List<EquipStatistics> statisticTime(String hostName, Date startTime, Date endTime) {
     46         
     47         List<EquipStatistics> equipStatisticsList = new ArrayList<EquipStatistics>();
     48         
     49         try {
     50             
     51         String initial = "{hostName:'' ,equipmentTypeName:'', userDurateion : 0,count:0,"
     52                 + "startTime:"+startTime.getTime()+",endTime:"+endTime.getTime()+",nowTime:"+new Date().getTime()+"}";
     53         
     54         String reduceFunction =  "function(doc,result){"
     55                 + "if(doc.extraData.hostName)   { result.hostName = doc.extraData.hostName;}"
     56                 + "if(doc.extraData.deviceType) {result.equipmentTypeName = doc.extraData.deviceType;}"
     57                 + "var time = doc.logoffTime.valueOf() - doc.logonTime.valueOf();"
     58                 + "result.userDurateion +=time;"
     59                 +" result.count+=1;"
     60                 + "}";
     61         
     62         //时间的计算分四种情况
     63         List<EquipStatistics> equipStatisticsListTemp =null;
     64         for (int i = 0; i < 4; i++) {
     65             switch (i) {
     66             case 0:
     67                 //登出时间在开始和结束之间,登录在开始和结束之间的(登出-登录)
     68                 Criteria criteria = Criteria.where("logonIp").exists(true);
     69                 if(hostName !=null && !"".equals(hostName.trim())){
     70                      criteria.and("extraData.hostName").regex(hostName);
     71                 }
     72                 criteria.and("logoffTime").lt(endTime).gt(startTime).and("logonTime").lt(endTime).gt(startTime);
     73                 equipStatisticsListTemp =  searchDB(criteria, reduceFunction, initial);
     74                 
     75                 break;
     76             case 1:
     77                 //1、 登出时间为空或 登出时间在结束之后, 登录时间在开始与结束之间的(结束-登录)
     78                 reduceFunction =  "function(doc,result){"
     79                         + "if(doc.extraData.hostName)   { result.hostName = doc.extraData.hostName;}"
     80                         + "if(doc.extraData.deviceType) {result.equipmentTypeName = doc.extraData.deviceType;}"
     81                         + "var time = result.endTime - doc.logonTime.valueOf();"
     82                         + "result.userDurateion +=time;"
     83                         +" result.count+=1;"
     84                         + "}";
     85                 Criteria criteria1 = Criteria.where("logonIp").exists(true);
     86                 if(hostName !=null && !"".equals(hostName.trim())){
     87                      criteria1.and("extraData.hostName").regex(hostName);
     88                 }
     89                 
     90                 criteria1.andOperator(Criteria.where("logonTime").lt(endTime).gt(startTime)
     91                         .andOperator(Criteria.where("logoffTime").exists(false).orOperator(Criteria.where("logoffTime").gt(endTime))));
     92                 equipStatisticsListTemp =  searchDB(criteria1, reduceFunction, initial);
     93                 break;
     94             case 2:
     95                 //2、 登出时间为空, 登出时间在结束之后  ,登录时间在开始之前的 (结束-开始) 
     96                 reduceFunction =  "function(doc,result){"
     97                         + "if(doc.extraData.hostName)   { result.hostName = doc.extraData.hostName;}"
     98                         + "if(doc.extraData.deviceType) {result.equipmentTypeName = doc.extraData.deviceType;}"
     99                         + "var time = result.endTime - result.startTime;"
    100                         + "result.userDurateion +=time;"
    101                         +" result.count+=1;"
    102                         + "}";
    103                 Criteria criteria2 = Criteria.where("logonIp").exists(true);
    104                 if(hostName !=null && !"".equals(hostName.trim())){
    105                      criteria2.and("extraData.hostName").regex(hostName);
    106                 }
    107                 criteria2.andOperator(Criteria.where("logonTime").lt(startTime)
    108                         .andOperator(Criteria.where("logoffTime").exists(false).orOperator(Criteria.where("logoffTime").gt(endTime))));
    109                 equipStatisticsListTemp =  searchDB(criteria2, reduceFunction, initial);
    110                 break;
    111             case 3:
    112                 //4、 登出时间在开始和结束之间,登录时间在开始之前的(登出-开始)
    113                 reduceFunction =  "function(doc,result){"
    114                         + "if(doc.extraData.hostName)   { result.hostName = doc.extraData.hostName;}"
    115                         + "if(doc.extraData.deviceType) {result.equipmentTypeName = doc.extraData.deviceType;}"
    116                         + "var time = doc.logoffTime.valueOf() - result.startTime;"
    117                         + "result.userDurateion +=time;"
    118                         +" result.count+=1;"
    119                         + "}";
    120                 Criteria criteria3 = Criteria.where("logonIp").exists(true);
    121                 if(hostName !=null && !"".equals(hostName.trim())){
    122                      criteria3.and("extraData.hostName").regex(hostName);
    123                 }
    124                 criteria3.and("logonTime").lt(startTime).and("logoffTime").lt(endTime).gt(startTime);
    125                 equipStatisticsListTemp =  searchDB(criteria3, reduceFunction, initial);
    126                 break;
    127             default:
    128                 break;
    129             }
    130             equipStatisticsList.addAll(equipStatisticsListTemp);
    131             equipStatisticsListTemp = null;
    132         }
    133         
    134         //去除重复数据 时长相加 赋值使用率
    135         equipStatisticsList = addDuration(equipStatisticsList,daysBetween(startTime,endTime));
    136         } catch (Throwable e) {
    137             logger.error("统计设备使用信息失败:"+e.getMessage(), e);
    138             throw new AssetRuntimeException(e);
    139         }
    140         
    141         
    142         return equipStatisticsList;
    143     }
    144     
    145     //获取相隔天数
    146     private int daysBetween(Date startTime, Date endTime) {
    147         return (int)((endTime.getTime()-startTime.getTime())/(1000 * 86400));
    148     }
    149 
    150 
    151     //查询数据库
    152     private List<EquipStatistics> searchDB(Criteria criteria, String reduceFunction,
    153             String initial) {
    154         List<EquipStatistics> equipStatisticsList = new ArrayList<EquipStatistics>();
    155         EquipStatistics equipStatistics = null;
    156         GroupBy groupBy = GroupBy.key("logonIp")
    157                 .initialDocument(initial)
    158                 .reduceFunction(reduceFunction);
    159         
    160         GroupByResults<Session> results = mongoTemplate.group(criteria,
    161                 "sessions", groupBy, Session.class);
    162         BasicDBList list = (BasicDBList)results.getRawResults().get("retval");  
    163         for (int i = 0; i < list.size(); i ++) {  
    164             equipStatistics = new EquipStatistics();
    165             BasicDBObject obj = (BasicDBObject)list.get(i);  
    166             equipStatistics.setIp(obj.getString("logonIp"));
    167             equipStatistics.setHostName(obj.getString("hostName"));
    168             equipStatistics.setEquipmentTypeName(obj.getString("equipmentTypeName"));
    169             equipStatistics.setUserDurateion(obj.getLong("userDurateion"));
    170             equipStatisticsList.add(equipStatistics);
    171         }
    172         return equipStatisticsList;
    173     }
    174     
    175 
    176     //去重
    177     private List<EquipStatistics> addDuration(List<EquipStatistics> equipStatisticsList,int days) {
    178         
    179         BigDecimal base = new BigDecimal(days*8*60*60*1000+"");
    180         
    181         if(equipStatisticsList!=null){
    182             for (int i = 0; i < equipStatisticsList.size()-1; i++) {
    183                 long userDurateion_i = equipStatisticsList.get(i).getUserDurateion();
    184                 equipStatisticsList.get(i).setUserdDurationStr(formatTime(userDurateion_i));
    185                 //
    186                 BigDecimal userDur_i = new BigDecimal(userDurateion_i);
    187                 double rate = userDur_i.divide(base, 4, BigDecimal.ROUND_HALF_UP).doubleValue();
    188                 equipStatisticsList.get(i).setUserRate(rate);
    189                 equipStatisticsList.get(i).setUserdRateStr(rate*100 + "%");
    190                 for(int j = equipStatisticsList.size()-1; j>i;j--){
    191                     long userDurateion_j = equipStatisticsList.get(j).getUserDurateion();
    192                     BigDecimal userDur_j = new BigDecimal(userDurateion_j);
    193                     rate = userDur_j.divide(base, 4, BigDecimal.ROUND_HALF_UP).doubleValue();
    194                     if(equipStatisticsList.get(i).getIp().equals(equipStatisticsList.get(j).getIp())){
    195                         equipStatisticsList.get(i).setUserDurateion(userDur_i.add(userDur_j).longValue());
    196                         equipStatisticsList.get(i).setUserdDurationStr(formatTime(userDur_i.add(userDur_j).longValue()));
    197                         rate = userDur_i.add(userDur_j).divide(base, 4, BigDecimal.ROUND_HALF_UP).doubleValue();
    198                         equipStatisticsList.get(i).setUserRate(rate);
    199                         equipStatisticsList.get(i).setUserdRateStr(rate*100 + "%");
    200                         equipStatisticsList.remove(j);
    201                     }else{
    202                         equipStatisticsList.get(j).setUserdDurationStr(formatTime(userDurateion_j));
    203                         equipStatisticsList.get(j).setUserRate(rate);
    204                         equipStatisticsList.get(j).setUserdRateStr(rate*100 + "%");;
    205                     }
    206                 }
    207             }
    208         }
    209         return equipStatisticsList;
    210     }
    211 
    212      /*
    213      * 毫秒转化时分秒毫秒
    214      */
    215     public String formatTime(Long ms) {
    216         Integer ss = 1000;
    217         Integer mi = ss * 60;
    218         Integer hh = mi * 60;
    219         Integer dd = hh * 24;
    220 
    221         Long day = ms / dd;
    222         Long hour = (ms - day * dd) / hh;
    223         Long minute = (ms - day * dd - hour * hh) / mi;
    224         Long second = (ms - day * dd - hour * hh - minute * mi) / ss;
    225         Long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss;
    226         
    227         StringBuffer sb = new StringBuffer();
    228         if(day > 0) {
    229             sb.append(day+"天");
    230         }
    231         if(hour > 0) {
    232             sb.append(hour+"小时");
    233         }
    234         if(minute > 0) {
    235             sb.append(minute+"分");
    236         }
    237         if(second > 0) {
    238             sb.append(second+"秒");
    239         }
    240         if(milliSecond > 0) {
    241             sb.append(milliSecond+"毫秒");
    242         }
    243         return sb.toString();
    244     }
    245 
    246     
    247 
    248   //测试代码
    249   
    250       public List getSessionTime() {
    251           try {
    252           CommandResult result =     mongoTemplate.executeCommand("{aggregate : 'sessions', pipeline : "
    253                   + "[{ $match : { logoffTime : {$exists:false} } },"
    254               //    + " { $group : { _id :logonIp,logonTime:{$sum:{logonTime.valueOf()}},logoffTime:{$sum:{logffTime.va}} } },"
    255                   + " {  $project : { _id : 0,logonHost : 1,logonIp : 1,logonTime : 1,extraData : 1,logoffTime : 1}}]}");
    256           System.out.println(result);    
    257               
    258           GroupBy groupBy = GroupBy.key("logonIp")
    259                   .initialDocument("{logonHost:'', sessionTime : 0, extraData : {}}")
    260                   .reduceFunction("function(doc,result){"
    261                           + "result.logonHost = doc.logonHost;"
    262                           + "var time = doc.logoffTime.valueOf() - doc.logonTime.valueOf();"
    263                           + "result.sessionTime +=time ;"
    264                           + "result.extraData = doc.extraData}");
    265           GroupByResults<Session> results = mongoTemplate.group(Criteria.where("logoffTime").exists(true),
    266                   "sessions", groupBy, Session.class);
    267           BasicDBList list = (BasicDBList)results.getRawResults().get("retval");  
    268           for (int i = 0; i < list.size(); i ++) {  
    269               BasicDBObject obj = (BasicDBObject)list.get(i);  
    270               System.out.println(obj.get("count"));  
    271           }  
    272           System.out.println(results);  
    273           }catch (Exception e) {
    274               System.out.println(e);
    275           }finally {
    276           try{
    277           MatchOperation matchOperation;
    278           
    279           matchOperation = new MatchOperation(Criteria.where("logonTime")
    280                       .lte(new SimpleDateFormat("yyyy-MM-dd").parse("2016-09-14"))
    281                       .gte(new SimpleDateFormat("yyyy-MM-dd").parse("2016-09-12"))
    282                       .andOperator(Criteria.where("logoffTime")
    283                       .lte(new SimpleDateFormat("yyyy-MM-dd").parse("2016-09-14"))
    284                       .gte(new SimpleDateFormat("yyyy-MM-dd").parse("2016-09-12")))
    285                       );
    286           
    287           GroupOperation groupOperation = new GroupOperation(Fields.fields("logonIp"));
    288           
    289           ProjectionOperation projectionOperation = new ProjectionOperation(Fields.fields("_id"));
    290           
    291           Aggregation aggregation = Aggregation.newAggregation(matchOperation,groupOperation,projectionOperation);
    292           
    293           AggregationResults<Object> groupResults 
    294               = mongoTemplate.aggregate(aggregation, "sessions", Object.class);
    295           
    296           List<Object> groupList =  groupResults.getMappedResults();
    297           for (Object object : groupList) {
    298               System.out.println(object.toString());
    299           }
    300           } catch (ParseException e) {
    301               e.printStackTrace();
    302           }
    303           }
    304           return null;
    305       }
    306     
    307 }
    EquipmentRepository.java
    //查询数据库
        private List<EquipStatistics> searchDB(Criteria criteria, String reduceFunction,
                String initial) {
            List<EquipStatistics> equipStatisticsList = new ArrayList<EquipStatistics>();
            EquipStatistics equipStatistics = null;
            GroupBy groupBy = GroupBy.key("logonIp")
                    .initialDocument(initial)
                    .reduceFunction(reduceFunction);
            
            GroupByResults<Session> results = mongoTemplate.group(criteria,
                    "sessions", groupBy, Session.class);
            BasicDBList list = (BasicDBList)results.getRawResults().get("retval");  
            for (int i = 0; i < list.size(); i ++) {  
                equipStatistics = new EquipStatistics();
                BasicDBObject obj = (BasicDBObject)list.get(i);  
                equipStatistics.setIp(obj.getString("logonIp"));
                equipStatistics.setHostName(obj.getString("hostName"));
                equipStatistics.setEquipmentTypeName(obj.getString("equipmentTypeName"));
                equipStatistics.setUserDurateion(obj.getLong("userDurateion"));
                equipStatisticsList.add(equipStatistics);
            }
            return equipStatisticsList;
        }

    分组查询主要使用org.springframework.data.mongodb.core.mapreduce.GroupBy这个spring中的类:

    例:

    GroupBy groupBy = GroupBy.key("logonIp")
    .initialDocument(initial)
    .reduceFunction(reduceFunction);
    GroupByResults<T> results = mongoTemplate.group(criteria,
    "sessions", groupBy, T.class);

    GroupBy.key('key'): key是所进行分组字段的字段名;

    initial : 初始化对象,可理解为最后查询返回的数据初始化;

    reduceFunction: js函数,用于对返回的结果进行处理操作;

    function(doc,result){}:

    doc是根据查询条件(相当于where条件)获取的每一条数据,result是最后的查询结果,初始值就是initial对象;

    查询操作:

    mongoTemplate.group(criteria,"session", groupBy, T.class);

    criteria:相当于SQL中的where条件;

    session: 数据库中的表名;

    groupBy: -以上;

    T.class: 这里是数据库表对应的domain

     BasicDBList list = (BasicDBList)results.getRawResults().get("retval")

    获取结果转为BasicDBList,"retval"是固定值,必须是它;

    BasicDBObject obj = (BasicDBObject)list.get(i);  obj.getString("key");

    key为initial中的key值,通过以上代码获取key值对应的value;

    这只是其中一种用法......

  • 相关阅读:
    servlet生命周期和线程安全
    如何保证Redis与数据库的数据一致性
    消息队列高可用、幂等性、顺序性、可靠性传输、堆积问题解决
    如何保证消息队列消息的顺序性
    RabbitMQ 如何保证消息不丢失?
    深入理解MySql事务
    MySQL/mariadb知识点总结
    如何实现一个线程安全的单例,前提是不能加锁
    DUBBO原理、应用与面经总结
    SpringBoot中资源初始化加载的几种方式
  • 原文地址:https://www.cnblogs.com/liangblog/p/5872243.html
Copyright © 2011-2022 走看看