mongodb常用的两种group方法,以及对结果排序

mongodb作为no-sql数据库的典型代表,拥有着存储海量数据的性能,在插入数据和查询数据方便也有着相对于其他关系型数据库明显的优势,最近学习了mongodb,发现mongodb中没有mysql中的group关键字,但是同样的以其他形式实现了对应的功能,下面总结了两种mongdb常用的group方法,介绍给大家。
第一种方法是利用管道来进行,管道是由一系列的功能节点组成的,当文档从一个操作节点流向下一个操作节点的时候,每个操作节点就会对文档做出相应的操作。主要是有两个功能,1,进行过滤,2,变换,也就是改变文档的输出形式。
主要是通过group,sum,avg,group来进行聚合求平均值以及进行求和操作。
Aggreagtion管道操作符主要有:
match:用于对文档集合进行筛选,之后就可以在筛选得到的文档子集中做聚合。
project:管道的投射,可以从子文档中提取字段,可以重命名字段
group:将文档根据特定的字段的不同值进行分组
unwind:可以将数组中的每一个值拆分为单独的文档。
这里举一个mongodb权威指南上的例子
一篇拥有多条评论的博客,利用unwind可以将每条评论都拆分为一个独立的文档。
sort:根据任何字段或者是多个字段可以进行排序,如果是大量的文档需要排序,建议在管道的第一阶段排序。
limit:接受一个数字n,返回结果集的前n个文档。
skip:接受一个数字n,丢弃结果集中的前n个文档,将剩余文档作为结果返回。
下面是利用管道的group使用以及mapreduce在mongodb中的使用

Mongo m = new Mongo(“localhost”:27017);
DB db = m.getDB(“test”);//test为数据库的名称
DBCollection coll = db.getCollection(“test”)//test为集合名称
//下面则就行构造管道中操作节点的操作符,主要用到的对象就是DBObject
DBObject match = new BasicDBObject("$match", new BasicDBObject("字段名", "字段值"));//限定查询条件,相当于Query,规定某个字段的值进行groupby
DBObject groupFields = new BasicDBObject(“_id”,”$字段名”);//也就是说groupby这个字段名
groupFields.put(“SumElectricty”,new BasicDBObject(“$sum”,”$字段名”));//对这个字段名的值进行求和,并且把这个和值生成一个名为SumElectricty的字段。
DBObject group = new BasicDBObject(“$group”,groupFields);
//放到管道中将这些节点运算符运算起来
AggregationOutput output = coll.aggregate(match,group);
//AggregationOutput 类有getCommandResult(),返回运行结果,结果是CommandResult,可以查看到。

mapreduce在mongodb中同样可以聚类,采用的是javascript作为查询语言,但是不得不承认的是,mapreduce非常慢,一般是不会用在实时的数据分析中的。这里做的是以在一个时间段内,对mac_id进行聚合,求字段electrity_quantity的和,并且排序显示出前n名。
起初我用的是比较笨的方法,并没有注意到query自身就可以进行排序并且还可以发挥前n个最大的结果集的能力。下面是这两个方法的代码。。

public Map groupbyId(Date d1,Date d2){
         double total = 0; 
         String reduce = "function(doc, aggr){" +  
 "            aggr.total += doc.electric_quantity;" +  
"        }"; //doc代表的是当前的文档,而aggr为之前所处理的文档的集合
        Query query = new Query();
        Criteria criteria = Criteria.where("record_time").gte(d1);//字段record_time的值大于等于d1
        criteria.and("record_time").lte(d2);//record_time的值小于等于d2
        query.addCriteria(criteria);//将条件插入到查询中
         DBCollection coll = mongoTemplate.getCollection("smartsocketer");//获得名为smartsocketer的集合
         DBObject result = coll.group(new BasicDBObject("mac_id", 1), query.getQueryObject(), new BasicDBObject("total", total), reduce);//groupby mac_id,在刚刚的查询条件下,执行reduce函数,并且将获得值放在名为total的字段中
         Map<String,BasicDBObject> map = result.toMap(); //将结果转换为k-v的map
        return map;


    }
public List<BasicDBObject> sortMapByValue(Map<String, BasicDBObject> oriMap,int n) {  
        List<BasicDBObject>  mappingList = new ArrayList<BasicDBObject>(); 
        if (oriMap != null && !oriMap.isEmpty()) {  
        Iterator it = oriMap.entrySet().iterator();//获得是文档
            while(it.hasNext()){
                Map.Entry<String,BasicDBObject> map = (Entry<String, BasicDBObject>) it.next();
                BasicDBObject dbob = map.getValue();
                dbob.entrySet();
                mappingList.add(dbob);
                }
       Collections.sort(mappingList, new Comparator<BasicDBObject>() {  
             public int compare(BasicDBObject entry1,  BasicDBObject entry2) {  
                            double value1 = 0, value2 = 0;  
                            try {  
  value1 = Double.parseDouble(entry1.getString("total"));
  value2 = Double.parseDouble(entry2.getString("total"));
                            } catch (NumberFormatException e) {  
                                value1 = 0;  
                                value2 = 0;  
                            }  
                           if(value1-value2<0)
                           {
                               return 1;
                           }
                           if(value1-value2>0)
                           {
                               return -1;
                           }
                           return 0;
                        }


                    }); 
                     }  
   return mappingList.subList(0, n);  //截取mappingList,而mappingList是排好序的list,直接截取就可以获得top; 
    }  

刚开始一直在困扰的是我在进行map排序的时候,实际上将map.entry放到list中去然后定义比较器比较entry的value就可以了,后来我发现group后发挥的map是下面这种形式的。
{1,{01,23.5}}
也就是说map的key值完全是索引,是自动生成的,并不是我所想到的mac_id字段值。
实际上就是BasicDBObject,因此直接定义这个对象的比较器就可以了。
当然更为简单的方法是利用query来做,在查询的时候就
query.with(new Sort(Direction.DESC, “字段名”));
上面就是两种方法,还有很多待补充的地方。挖坑第一天,一定要坚持下去>:<

你可能感兴趣的:(数据库)