mongodb先条件查询与再分组

来源:互联网 发布:制作微电影的软件 编辑:程序博客网 时间:2024/05/16 13:53

如果你已经搜索到了这个页面,那我很不幸的告诉你,java mongodb的查询不仅慢,而且很繁琐,你的噩梦才刚刚开始。

    先简单地介绍下,我要实现的功能。

    本人一直在做网站运维这块,在统计网站数据的过程中,需要计算PV、UV,时间单位是一天,很自然就需要用到条件查询,查询一天的情况。

    先看PV,查询某日总的页面访问量,面向页面计算。

[java] view plain copy
  1.      /** 
  2. * 查询某日PV量(总的页面访问量,面向页面) 
  3. * @param date 
  4. * @return PV量 
  5. */  
  6. ublic static int getPV(String strDate){  
  7.   
  8. BasicDBObject query = new BasicDBObject();  
  9.   
  10. int PV = 0;  
  11.   
  12. String condition = Condition.getTimeCond(strDate);  
  13.   
  14. query.put("$where",condition);  
  15.   
  16. dbCol = init();  
  17.   
  18. DBCursor cursor = dbCol.find(query);  
  19.   
  20. while (cursor.hasNext()) {  
  21.       
  22.     System.out.println(cursor.next());;  
  23.       
  24. }  
  25.   
  26. PV = cursor.count();  
  27.   
  28. return PV;  
     再看UV,我以cookie中的UUID为标准,作为独立访客,00:00-24:00内相同的客户端只会被计算一次。 
[java] view plain copy
  1.       /** 
  2.  * UV(独立访客数)00:00-24:00内相同的客户端只会被计算一次 
  3.  * @param strDate 
  4.  * @return UV量 
  5.  */  
  6. public static int getUV(String strDate){  
  7.       
  8.     BasicDBObject query = new BasicDBObject();  
  9.       
  10.     int UV = 0;  
  11.       
  12.     dbCol = init();  
  13.       
  14.     String condition = Condition.getTimeCond(strDate);  
  15.   
  16.     query.put("$where",condition);  
  17.     //根据uuid去重,查询  
  18.     UV = dbCol.distinct("uuid",query).size();  
  19.       
  20.     return UV;  
  21. }  
    如果你想偷懒,直接cope过去使用,肯定会报错的,呵呵呵!

    我来稍带讲一下:

    两个函数中的参数strDate,是你查询的日期,比如“2014-04-11”;

    dbCol,是获取的集合对象,也就是DBCollection,这里不废话了,不知道的可以留言;

    query,大家注意这个对象,它是用来临时条件查询中的条件,如果多个条件,也可以这样

[javascript] view plain copy
  1. 条件列表:  
  2. BasicDBList condList = new BasicDBList();   
  3.   
  4. //年龄大于1小于100  
  5. BasicDBObject cond1= new BasicDBObject();  
  6.   
  7. cond1.append("age",new BasicDBObject("$gt",1));  
  8.   
  9. cond1.append("age",new BasicDBObject("$lte",100));  
  10.   
  11. //性别为女  
  12. BasicDBObject cond2= new BasicDBObject();  
  13.   
  14. cond2.append("sex","女");  
  15.   
  16. //将两个条件加入到条件集合中(多条件)  
  17. condList.add(cond1);  
  18.   
  19. condList.add(cond2);  
  20.   
  21. BasicDBObject cond= new BasicDBObject();  
  22.   
  23. cond.put("$and", condList);  
  24.   
  25. 然后查询数据:  
  26. DBCursor cursor= coll.find(cond);  
    condition,大家可能注意到了,这个对象是关键,标准的where条件从句,现在我将方法展示如下:
[javascript] view plain copy
  1.    /** 
  2.     * 条件查询时间条件 
  3.     * @param strDate 
  4.     * @return 
  5.     */  
  6.    public static String getTimeCond(String strDate){  
  7.       
  8. long mintime = DataFormat.stringToMills(strDate);  
  9.       
  10. long maxtime = mintime+86400000;  
  11.       
  12. return  "function(){"  
  13.       
  14.         +"var init = this.initTime.replace(new RegExp('-','gm'),'/'); "   
  15.                          
  16.         +"var initMills = (new Date(init)).getTime();"   
  17.                          
  18.         +"return initMills>"+mintime+"&&initMills<"+maxtime+";}" ;  
  19. }  
  20.     }  
     我将where条件用一个javascript函数返回,为什么可以这样呢,因为JSON是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON数据不须要任何特殊的 API 或工具包,而mongodb存的就是类json数据(bson)。

    还有在这里,我是把时间转换为了毫秒进行大小比较的!

    最后一点,distinct函数,对就是sqlserver中的去重,很好用。

    另外,讲讲分组。

    先上代码:

[java] view plain copy
  1. //返回条件查询的游标  
  2. DBCursor cursor = dbCol.find(query);  
  3.   
  4. List<Map<String, String>> listOfMaps = new ArrayList();  
  5.   
  6. //将游标中返回的结果记录到list集合中  
  7. while (cursor.hasNext()) {  
  8.   
  9.  listOfMaps.add((Map<String, String>) cursor.next());  
  10.   
  11. }  
  12.     
  13. //第一次分组,根据uuid分组  
  14. Multimap<String, Map<String, String>> partitionedMap = Multimaps.index(  
  15.      listOfMaps,new Function<Map<String, String>, String>() {  
  16.            public String apply(final Map<String, String> from) {  
  17.                   return from.get("uuid");  
  18.           }  
  19.      });  
  20. //将指定uuid下的每条记录添加到list集合中  
  21. List<Map<String, String>> useList = (List<Map<String, String>>) partitionedMap.get(uuid);  
    不知道大家有没有用过guava,谷歌自创的map,很好用的。

    官网:https://code.google.com/p/guava-libraries/

    开源社区也有部分中文资料可供参考:http://www.oschina.net/question/tag/guava

    uuid是本人在mongodb中一个字段名。

    简单讲一下思路:先将条件查询获取的游标(只是指针)的结果遍历出来,然后放入一个List中,最后把list放入谷歌的Multimap中,就会返回分组后的结果(DEMO中from.get("uuid")是以“uuid”来分组的),当然也可以多次分组,一层一层分,事实上,本人就用了三次分组,原理一样。

    欢迎大家留言!