统计Mongo数组中相同对象的属性之和

需求

需要统计app端用户的行为,按天分表,存入mongo。每次用户进行操作的时候,将数据存入app本地,下次用户启动的时候,提交存入mongo,删除app本地缓存。那么用户这个行为的文档就算是很复杂了。举个例子,存入mongo中文档为

/* 1 */
{
"_id" : ObjectId("5b8c996e5f814eb3c37eb49b"),
"userId" : 12323.0,
"appPlatform" : "ios",
"shortcutEntrance" : [
{
"entranceName" : "入口1",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"entranceName" : "入口2",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"classData" : [
{
"classId" : 123.0,
"position" : "left",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"classId" : 12356.0,
"position" : "right",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"channelVisit" : [
{
"channelType" : 2.0,
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"channelType" : 3.0,
"gmtCreate" : "2018-09-03 10:00:00"
}
]
} /* 2 */
{
"_id" : ObjectId("5b8e163df0fad825a708bc75"),
"userId" : 12323.0,
"appPlatform" : "ios",
"shortcutEntrance" : [
{
"entranceName" : "入口1",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"entranceName" : "入口2",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"classData" : [
{
"classId" : 123.0,
"position" : "left",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"classId" : 12356.0,
"position" : "right",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"channelVisit" : [
{
"channelType" : 2.0,
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"channelType" : 3.0,
"gmtCreate" : "2018-09-03 10:00:00"
}
]
} /* 3 */
{
"_id" : ObjectId("5b8e1642f0fad825a708bc76"),
"userId" : 12323.0,
"appPlatform" : "ios",
"shortcutEntrance" : [
{
"entranceName" : "入口1",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"entranceName" : "入口2",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"classData" : [
{
"classId" : 1234.0,
"position" : "left",
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"classId" : 12356.0,
"position" : "right",
"gmtCreate" : "2018-09-03 10:00:00"
}
],
"channelVisit" : [
{
"channelType" : 2.0,
"gmtCreate" : "2018-09-03 10:00:00"
},
{
"channelType" : 3.0,
"gmtCreate" : "2018-09-03 10:00:00"
}
]
}

那么我需要统计classData.classId 相同的有多少。

解决方案

  1. 先对过滤出自己需要的数据
   {"$project":{"classData.classId":1,"classData.position":1}}

获得得数据如下:

/* 1 */
{
"_id" : ObjectId("5b8c996e5f814eb3c37eb49b"),
"classData" : [
{
"classId" : 123.0,
"position" : "left"
},
{
"classId" : 12356.0,
"position" : "right"
}
]
} /* 2 */
{
"_id" : ObjectId("5b8e163df0fad825a708bc75"),
"classData" : [
{
"classId" : 123.0,
"position" : "left"
},
{
"classId" : 12356.0,
"position" : "right"
}
]
} /* 3 */
{
"_id" : ObjectId("5b8e1642f0fad825a708bc76"),
"classData" : [
{
"classId" : 1234.0,
"position" : "left"
},
{
"classId" : 12356.0,
"position" : "right"
}
]
}

_id 默认为1 也就是

   {"$project":{"_id":1,"classData.classId":1,"classData.position":1}}
  1. 对classData数组进行分类切分
 {"$unwind":"$classData"}

获取数据如下:

/* 1 */
{
"_id" : ObjectId("5b8c996e5f814eb3c37eb49b"),
"classData" : {
"classId" : 123.0,
"position" : "left"
}
} /* 2 */
{
"_id" : ObjectId("5b8c996e5f814eb3c37eb49b"),
"classData" : {
"classId" : 12356.0,
"position" : "right"
}
} /* 3 */
{
"_id" : ObjectId("5b8e163df0fad825a708bc75"),
"classData" : {
"classId" : 123.0,
"position" : "left"
}
} /* 4 */
{
"_id" : ObjectId("5b8e163df0fad825a708bc75"),
"classData" : {
"classId" : 12356.0,
"position" : "right"
}
} /* 5 */
{
"_id" : ObjectId("5b8e1642f0fad825a708bc76"),
"classData" : {
"classId" : 1234.0,
"position" : "left"
}
} /* 6 */
{
"_id" : ObjectId("5b8e1642f0fad825a708bc76"),
"classData" : {
"classId" : 12356.0,
"position" : "right"
}
}

那么这样了就很好去获取classId得总数了

{"$group":{_id:"$classData.classId","classIdSum":{"$sum":1}}}

获取数据如下

/* 1 */
{
"_id" : 1234.0,
"classIdSum" : 1.0
} /* 2 */
{
"_id" : 12356.0,
"classIdSum" : 3.0
} /* 3 */
{
"_id" : 123.0,
"classIdSum" : 2.0
}

总命令如下:

db.getCollection('SHORTCUT_ENTRANCE_20180903').aggregate(
[
{"$project":{"classData.classId":1,"classData.position":1}},
{"$unwind":"$classData"},
{"$group":{_id:"$classData.classId","classIdSum":{"$sum":1}}}
])

数据统计存入业务表

结合Spring,使用mongoTemplate:

  • 配置数据源
 <!-- 数据源 -->
<mongo:db-factory id="mongoDbFactory" uri="mongodb://${mongo.database}:${mongo.password}@${mongo.host}:${mongo.port}/${mongo.username}?maxPoolSize=2000"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
  • 从mongo获取统计数据存入业务表

核心代码如下:

Aggregation agg = Aggregation.newAggregation(
Aggregation.project("classData.classId","classData.position"),
Aggregation.unwind("$classData"),
Aggregation.group("$classData.classId").count().as("sim")
) AggregationResults<BasicDBObject> objects = mongoTemplate.aggregate(agg,collection,BasicDBObject.class);//获取需要的统计数据
Iterator<BasicDBObject> iterator = objects.iterator();
while(iterator.hasNext()){
DBObject object = iterator.next();//获取统计数据中单个集合
........ //业务逻辑 存入业务表
}

统计Mongo数组中相同对象的属性之和的更多相关文章

  1. [原创]java WEB学习笔记59:Struts2学习之路---OGNL,值栈,读取对象栈中的对象的属性,读取 Context Map 里的对象的属性,调用字段和方法,数组,list,map

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  2. HTML中DOM对象的属性和方法的层级关系是怎样的?(目录即层次)

    HTML中DOM对象的属性和方法的层级关系是怎样的?(目录即层次) 一.总结 一句话总结:目录就是测试题 1.document取得元素(get element)的方式有哪几种? 解答:四种,分别是id ...

  3. Java如何从数组中查找对象元素?

    在Java中,如何从数组中查找对象元素? 示例 以下示例使用Contains方法来搜索数组中的String对象. package com.yiibai; import java.util.*; pub ...

  4. 统计numpy数组中每个值出现的个数

    统计numpy数组中某一个值或某几个值出现的个数:sum(data==4) # 统计出现了几个cluster include0Cluster = sum(res == 0) include1Clust ...

  5. 将对象的所有属性名放到一个数组中 || 获得对象的所有属性名 || return;不具有原子性 || 怎样自己制作异常|| 判断对象有没有某个属性 || 当传递的参数比需要的参数少的时候,没有的值会被赋予undefined || 获得函数实际传递的参数 || 怎么用函数处理一个对象 || 用一个名字空间定义一个模块所有的函数 || 给一个对象添加方法

    获得对象的所有属性名 || 将对象o的所有属性名放到数组中 var o = {x:1,y:2,z:3}; var arr = []; var i = 0; for(arr[i++] in o){};/ ...

  6. 你好,C++(38)从问题描述中发现对象的属性和行为 6.4 工资程序成长记:类与对象(上)

    6.4  工资程序成长记:类与对象 “夜半三更哟,盼天明:寒冬腊月哟,盼春风.若要盼得哟,涨工资,岭上……”自从上次老板许诺给小陈涨工资以后,一转眼又过去几个月了,可是涨工资的事一点动静都没有.小陈只 ...

  7. iOS 查询数组中的对象

    简述:Cocoa框架中的NSPredicate用于查询,原理和用法都类似于SQL中的where,作用相当于数据库的过滤取. 定义(最常用到的方法): NSPredicate *ca = [NSPred ...

  8. 全面理解Javascript中Function对象的属性和方法

    http://www.cnblogs.com/liontone/p/3970420.html 函数是 JavaScript 中的基本数据类型,在函数这个对象上定义了一些属性和方法,下面我们逐一来介绍这 ...

  9. JS中访问对象的属性

    方式一: 对象名.属性名;   方式二: 对象名["属性名"];   ★注意:方式二中,属性名以字符串的形式出现在方括号中,这意味着通过方式二访问属性的话,可以实现“动态访问对象的 ...

随机推荐

  1. 音视频处理之PS封装的介绍与使用20180928

    1.PS封装介绍MPEG2-PS是一种多路复用数字音频,视频等的封装容器.PS是Program Stream(程序流或节目流)的简称.程序流将一个或多个分组但有共同的时间基准的基本数据流(PES)合并 ...

  2. EasyUI 格式化列

    以下实例格式化在 easyui DataGrid 里的列数据,并使用自定义列的 formatter,如果价格小于 20 就将文本变为红色. 为了格式化一个数据网格(DataGrid)列,我们需要设置 ...

  3. std::bind常见的坑

    http://note.youdao.com/noteshare?id=bce9cdea8e94501186b5ba3026af685f

  4. Scala进阶之路-面向对象编程之类的成员详解

    Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...

  5. 配置httpd2.4与常见的I/O模型说明

    配置httpd2.4与常见的I/O模型说明 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.httpd2.4访问控制 1.基于IP访问控制: 允许所有主机访问:Require a ...

  6. SQL语句(十一)函数查询

    (十一)函数查询 1. 聚合函数 对一组值进行计算,得到一个返回值 SUM(), 求和 AVG(), 求平均 MIN(), 求最小 MAX(), 求最大 COUNT(), 计数,即个数 --例1 求所 ...

  7. FFprobe使用指南

    http://blog.csdn.net/stone_wzf/article/details/45378759 http://blog.chinaunix.net/uid-26000296-id-42 ...

  8. C根据排序字符串

    #include<stdio.h> #include<string.h> #include <stdlib.h> #define STR_LEN_MAX 100 c ...

  9. java concurrent 中ExecutorService和CompletionService简单区别

    举个例子,现在需要执行10个任务,这些任务都是有返回值,并且需要使用10个线程同时执行.一般的做法就是创建ExecutorService线程池,pool大小10,每个任务实现Callable接口,然后 ...

  10. 关于如何在Python中使用静态、类或抽象方法的权威指南

    Python中方法的工作方式 方法是存储在类属性中的函数,你可以用下面这种方式声明和访问一个函数 >>> class Pizza(object): ... def __init__( ...