作者回复: 这个问题需要一些时间,所以回复晚了一点。
## 数据模型
测试数据:
```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有可以在内存做计算的特性,如果你可以把你的数据都放在内存,那么聚合运算的性能大概率可以不错。
如果你有数千万数亿以上的行数要做扫描性汇聚,又是跑在机械盘,索引又没有优化,那么有可能是分钟级的聚合计算性能。
作者回复: 非常棒!
作者回复: MongoDB里面貌似实现不了这么高级的计算,可能只能拉到内存里。这么大的量的话,要用到spark来做并发计算然后再把结果写回去mongodb。
作者回复: > Timestamp(1574326231, 1).getTime()
157432623
作者回复: 你先说说看为什么B+树更合理,我在回复你 ;-)
作者回复: 视频课程提供课件,其他更多的内容可以去到docs.mongodb.com 上面有很详尽的参考。如果对某些地方不是很理解可以提问。
作者回复: 可能需要看你的数据,及实际的输出。这个条件看上去没什么问题
作者回复: 这个是MongoDB的物理限制,目前除了分文档之外没有别的解决方案。
作者回复: 目前还不支持
作者回复: 这个需要你提供具体的查询语句。可以加上explain,如:
db.orders.explain().aggregate( [...])
然后看看是什么样的慢
作者回复: 你在你的find 里面加上同样的sort试试。
作者回复: 假设数据模型是:
```javascript
db.testData.insertMany([{
areaCode: "Shanghai",
sales: 100
}, {
areaCode: "Beijing",
sales: 120
}, {
areaCode: "Shenzhen",
sales: 130
}, {
areaCode: "Shenzhen",
sales: 120
}, {
areaCode: "Shenzhen",
sales: 100
}, {
areaCode: "Beijing",
sales: 100
}]);
```
要计算每个地区的top1,需要将数据按照地区和销量排序,然后取每个分组(即每个地区)的`$first`:
```javascript
db.testData.aggregate([{
$sort: {
areaCode: 1,
sales: -1
}
}, {
$group: {
_id: "$areaCode",
topSales: {
$first: "$sales"
}
}
}]);
```
参考:
- `$first`: https://docs.mongodb.com/manual/reference/operator/aggregation/first/
- `$group`: https://docs.mongodb.com/manual/reference/operator/aggregation/group/
作者回复: 没太看懂,用例子试下?