工作两年了,从来没写过博客,现在想想是时候写写平时工作中遇到的问题了。脑子不好使,还是笔头好啊。

废话不多说,现在工作要求使用mongodb-初识mongodb还得从简单的命令开始,增删改查。现在要实现一个分组统计的功能,背景如下:

活动分布者1---->n活动---->n活动报名用户【同一个活动一个人报名一次openid区分】

现在想在页面展现【当前发布者】【根据openid分组】【然后取每组最近时间的】【报名用户的相信信息】

分析可知:先要有一个条件查询,一个group,一次排序,取最近时间,还要有详细信息,然后还必须支持分页!

查了很多竟然没有搜到我这个需求的,我觉得这个需求经常用到才是,没办法自己拿着mongodb权威指南啃,发现了mapreduce可以实现,具体实现如下:


db.applyuser.runCommand({
    'group':{
        'ns':'applyuser'--指定要分组的集合名称
        'key':{'openid':true},--文档分组的依据
         'initial':{'applyTime':0},--初始化数据,applyTime每组初始为0
        '$reduce':function(doc,prev){--reduce,分组后,每组内数据执行,取最新时间
                if(doc.applyTime > prev.applyTime){
                    prev._id = doc._id;
                    prev.headimgurl = doc.headimgurl;
                    prev.name = doc.name;
                    prev.phone = doc.phone;
                    prev.applyCount = doc.applyCount;
                }},
        'condition':{'staffID':'214be1c2bcba486faaa4c329afcf479b','$where':'function(){return this.applyCount < 5}'},--条件查询,可嵌套where查询
        }
})



但是上面方式有个缺点是无法分页,我试了很多也没有发现他支持分页?无法分页不符合需求,遂继续寻找解决方案

利用mongodb的管道技术查询,刚开始的时候其实就考虑使用管道,无奈当进行到group时不知道怎样进行,因为一旦根据某个字段group以后,得到的结果集里只有该字段的信息,而我需要的是分组后每组最近时间的那一条记录信息【页面需要展示什么字段就得查询出来哪些字段】仔细看书终于找到解决方案:

db.applyuser.aggregate(
{
"$sort":{"applyTime":1}--按时间排序
},{
"$group":{"_id":"$openid","id1":{"$first":"$_id"},"name":{"$first":"$name"}}--按openid分组,取每组内的first的name赋给name
},{
"$limit":5--结果集返回五条数据
},{
"$skip":1--跳过第一条数据,从第二条数据开始
}
)

以下为对应的spring-mongotemplate查询方法

TypedAggregation<ApplyUser> agg = Aggregation.newAggregation(
        ApplyUser.class
        , Aggregation.match(c)
        , Aggregation.sort(new Sort(Sort.Direction.DESC, "applyTime"))
        , Aggregation.group("openid")
                .first("id").as("aliasID")
                .first("email").as("email")
                .first("country").as("country")
                .first("province").as("province")
                .first("city").as("city")
                .first("name").as("name")
                .first("sex").as("sex")
                .first("actTitle").as("actTitle")
                .first("applyCount").as("applyCount")
                .first("phone").as("phone")
                .first("openid").as("openid")
                .first("headimgurl").as("headimgurl")
        , Aggregation.skip(page.getFirstResult())
        , Aggregation.limit(page.getPageSize())
);
AggregationResults aggResults = mongoTemplate.aggregate(agg, SystemContent.COLLECTION_NAME_APPLYUSER, ApplyUser.class);


有个问题就是执行下面后结果集中的_id的值是分组字段的值,封装到对象中没有获得到真实的id,但是页面展现的操作还都需要这唯一ID,我暂时是新建了个aliasID用来存储,不知道各位有别的方式吗?

Aggregation.group("openid")