作者回复: 这个问题需要一些时间,所以回复晚了一点。 ## 数据模型 测试数据: ```javascript db.test.insertMany([ { messageType: '01', date: ISODate("2019-01-01T01:15:42Z") // 其他字段 }, { messageType: '01', date: ISODate("2019-01-01T01:17:42Z") }, { messageType: '02', date: ISODate("2019-01-17T01:17:42Z") }, { messageType: '02', date: ISODate("2019-01-17T02:17:42Z") }, ]) ``` ## 解决思路 1. 从日期中提取日期和小时。这里如果有必要,需要考虑时区问题。如果考虑时区问题,则需要3.6以上版本支持; 1. 按日期、小时分组聚合; 使用到的运算符: - [$dateToString](https://docs.mongodb.com/manual/reference/operator/aggregation/dateToString/) - [$year](https://docs.mongodb.com/manual/reference/operator/aggregation/year/) - [$month](https://docs.mongodb.com/manual/reference/operator/aggregation/month/) - [$dayOfMonth](https://docs.mongodb.com/manual/reference/operator/aggregation/dayOfMonth/) ## 聚合语句 ```javascript db.test.aggregate([ // 过滤条件(如果有) { $match: { date: { $gte: ISODate("2019-01-01T00:00:00Z"), $lt: ISODate("2019-02-01T00:00:00Z"), } } }, // 映射出日期和小时 { $project: { date: { $dateToString: { date: "$date", format: "%Y-%m-%d", timezone: "+08:00" } }, hour: { $hour: "$date" }, messageType: 1 } }, { // 按日期、小时、messageType分组计数 $group: { _id: { date: "$date", hour: "$hour", messageType: "$messageType" }, count: { $sum: 1 } } } ]); ```
作者回复: 谢谢。后续章节会涉及一些设计方面的。但是本课程的目标确实是偏应用方面多一点。源码底层内容太多,可能需要另外的课程来覆盖。
作者回复: 你可以打破常规思维考虑。国家的名称你多长时间需要改一次呢?当然,商品名称修改频率会略高一些,但也是低频动作。MongoDB已经提供多表多行事务来保证修改的一致性。另外如果是经常要改的内容,也还是可以按照关系设计,并不是绝对要放到一张表里面。
作者回复: 非常棒!
作者回复: 这个范围很广。我们的客户中最大的有100TB的数据量上做聚合的(Amadeus)。当然那个是32台物理服务器和288个微分片的架构,比较复杂了。 通常来说MongoDB有可以在内存做计算的特性,如果你可以把你的数据都放在内存,那么聚合运算的性能大概率可以不错。 如果你有数千万数亿以上的行数要做扫描性汇聚,又是跑在机械盘,索引又没有优化,那么有可能是分钟级的聚合计算性能。
作者回复: 需要使用条件判断,有一点点绕: db.test.aggregate([ { $group: { _id: "$group", success: { $sum: { $cond: { if: { $eq: [ "$status", "SUCCESS" ] }, then: 1, else: 0 } } }, failure: { $sum: { $cond: { if: { $eq: [ "$status", "FAILURE" ] }, then: 1, else: 0 } } } } } ])
作者回复: MongoDB里面貌似实现不了这么高级的计算,可能只能拉到内存里。这么大的量的话,要用到spark来做并发计算然后再把结果写回去mongodb。
作者回复: > Timestamp(1574326231, 1).getTime() 157432623
作者回复: 这么没信心。。。 如果计算的结果太大, 超过16MB,或者需要在内存进行排序或其他计算的时候超过100MB,聚合操作会失败。通常的做法是避免对非索引字段进行排序,或者使用allowDiskUse选项来突破100MB的限制。 另外,考虑在从节点上进行这样的聚合操作。否则会影响其他的数据库操作业务。
作者回复: 这个是MongoDB的物理限制,目前除了分文档之外没有别的解决方案。