java 使用mongoTemplate 按月分组、聚合的实现 (要求返回非分组字段)_deelless的博客-程序员宅基地_mongotemplate 分组

技术标签: mongoDB技术篇  

一.需求

统计当前用户过去一年中每个月新增联系人(联系人表存储在mongoDB)

二.分析:

根据createTime 中的月分组,聚合返回字段有:用户id,分组月份,该月记录条数

三:mongo 查询语句

在这里插入图片描述

说明:
$project:映射,查询的字段,1显示,0不显示
$match:过滤,查询条件(相当于sql中的where)
$group:分组,这里用到了 mongo 自带的 $month函数,可以根据createTime中的月分组
注意
分页、排序等语句可以在后面累加;
映射,过滤,分组,分页,排序等有顺序,顺序可以改变,下层在上层的基础上处理数据(管道);

三.java mongoTemplate实现

public AggregationResults<ContactMember> findContactMemberGroupMonth(Date date,Integer userId){
        //查询条件
        Criteria criteria=new Criteria();
        //封装查询日期,gte大于等于
        criteria.and("createTime").gte(date);
        //分组对象
        Aggregation aggregation=Aggregation.newAggregation(
                //添加过滤条件
                Aggregation.match(criteria),
                //查询字段,andExpression(xx).as(yy) 表示将查询字段中的yy替换为xx
                //这里用到了 month函数,需要替换
                Aggregation.project("createTime","userId").andExpression("{$month: '$createTime'}").as("createTime"),
                //根据createTime分组
                //first为 当前列聚合时取多条数据中的第一条
                Aggregation.group("createTime").first("createTime").as("monthNum").count().as("monthCount").first("userId").as("userId")
        );
        //本项目根据userId进行了分表,所以对mongoTemplate进行了封装
        //底层调用 mongoTemplate.aggregate(aggregate, colName, ContactMember.class);
        return super.aggregateResult(aggregation,userId);

    }

四.测试

 @Test
    public void testFindContactMemberGroupMonth(){
        Calendar instance = Calendar.getInstance();
        //过去一年
        instance.add(Calendar.YEAR,-1);
        AggregationResults<ContactMember> groupMonth = contactMemberService.findContactMemberGroupMonth(instance.getTime(),15);
        System.out.println("test123:"+groupMonth.getMappedResults().size());
        System.out.println("test124:"+groupMonth.getMappedResults().get(0));
    }
测试通过(用户id为15的用户10月增加的联系人有5个,和数据库查询结果一致),打印结果:
test123:2
test124:ContactMember{id='10', listId=null, userId=15, email='null', phone='null', name='null', createTime=null, updateTime=null, properties=null, grade='null', importBatchNo='null', tags=null, monthCount=5, monthNum=10}

补充

关于分组和聚合

分组指的是将满足相同条件的数据变为一条(组)数据
比如createTime 创建时间为 2020年的11月有10条数据,若根据createTime 为2020年11月分组,分组后createTime字段唯一,其他字段不一定唯一,其他字段怎么显示呢?这里要用到聚合函数
聚合指的是多个数据如何取值
常见的聚合函数有:sum(求和),max(取最大值),min(最小值),avg(平均值),first(第一个),last(最后一个),count(记录条数)等
本例聚合的所有userId都相同,所以使用first函数即可

mongoDB文档:https://docs.mongodb.com/v2.4/reference/operator/aggregation/project/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43078114/article/details/109841945

智能推荐

idea变量显示val解决方案_chezhimi6410的博客-程序员宅基地

解决方法:在plugin里去掉advanced java folding这个插件 左上角-&gt;file-&gt;settings-&gt;plugin-&gt;把advanced java folding后面的√去掉重启IDEA就OK了 ...

PinyinUtil_涂作权的博客的博客-程序员宅基地

package com.css.common.util;import java.util.ArrayList;/** * 拼音信息处理类 *  * @version 1.0 * */public class PinyinUtil {  /**  * 拼音集合信息  */ public static ArrayList pinyin = new A

优化工具 Neos Server_chuifuhuo6864的博客-程序员宅基地

我觉得Neos server 是很不错的东东,想做优化的童鞋可以试试哦。 下面只是个人发牢骚了(非常罗嗦,珍惜时间者莫看): 首先因为我的问题是非严格凸函数,所以我还是决定尝试一下Matlab+CVX。于是写了一堆for循环,matlab的for循环不是一般的速度啊,我估计一...

java 双分派_访问者模式讨论篇:java的动态绑定与双分派_weixin_39632471的博客-程序员宅基地

java的动态绑定所谓的动态绑定就是指程执行期间(而不是在编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。java继承体系中的覆盖就是动态绑定的,看一下如下的代码:classFather {public voidmethod(){System.out.println("This is Father's method");}}class Son1 extendsFather{p...

用java实现简单的计算器(基于Calculator)_竦貊的博客-程序员宅基地

关于Calculator的实现和安装,请参见大神博客:https://www.cnblogs.com/woider/p/5331391.html转载请注明出处我只是在次基础上,借了一下“轮子”。再次感谢大神。只要是按钮上有的,本计算器都可以支持的哦!成品截图:这里给出文件分布图:Java可执行文件链接https://coding.net/u/ping...

MySQL基础学习(三)-记录操作_NEFU菜鸟的博客-程序员宅基地

MySQL基础(三)-记录操作1 插入记录INSERT [INTO] tbl_name [(col_name,...)] {VALUES | VALUE} ({expr|DEFAULT},...),(...)案例分析mysql&amp;gt;CREATE TABLE users(id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,u...

随便推点

linux内核之关于内存屏障_如小丧的博客-程序员宅基地

文章一:前言之前读了关于顺序一致性和缓存一致性讨论的文章,感觉豁然开朗。对linux内核中出现的种种同步和屏障,想做一点总结。缓存一致性之前一直认为linux中很多东西是用来保证缓存一致性的,其实不是。缓存一致性绝大部分是靠硬件机制实现的,只有在带lock前缀的指令执行时才与cache有一点关系。(这话说得绝对,但我目前看来就是这样)我们更多的时候是为了

一个关于wcscpy和wcscpy_s的问题_我只是一只狗的博客-程序员宅基地

wcscpy()即为strcpy()的宽字符版本(Unicode),与_T类似的,Visual C++提供了类似的同名函数: #ifdef UNICODE #define _tcscpy wcscpy #else #define _tcscpy strcpy #endif wcscpy_s的作用和前面一样,不过是MS搞出来的带有

Myeclipse SVN错误:Error validating server certificate for https//_yixiaoping的博客-程序员宅基地

Error validating server certificate for https://192.168.0.20:8443:- Unknown certificate issuer   Fingerprint: 0c:44:1c:76:dc:c6:ec:55:2f:a8:90:1c:e5:31:7d:e5:17:8f:de:24   Distinguished name: sv

从噪声标签中学习_xys430381_1的博客-程序员宅基地

综述:Image classification with deep learning in the presence of noisy labels: A survey-2019对应的解读:学习噪声(Deep Learning Noisy Labels)Resource:Awesome-Learning-with-Label-Noise https://github.com/gorkemalgan/deep_learning_with_noisy_labels_lit

黑马程序员_java_面向对象_异常处理_透过生活的博客-程序员宅基地

  ------- http://www.itheima.com" target="blank">android培训、http://www.itheima.com" target="blank">java培训、期待与您交流! ---------- 一、异常体系的特点: 异常体系中所有的类及对象都具有可抛性,都可以被throw和throws所修饰。只有异常类具有这

Java DB的两种连接方式_dusin的博客-程序员宅基地

Derby有两种连接方式    第一种连接方式就是像MySQL、Oracle、SQL Server这样使用连接字符串进行连接的Network工作方式,其默认端口为1527。连接串写一写昂:            jdbc:derby://localhost:1527/[;属性1=属性值1[;...]]    第二种连接方式就可以用来替代Access这样“本地数据库”的Embedded形