我使用Mongo作为tick数据库,我定期将数据放入时间戳。后来我使用这些数据来查询有关系统的统计信息。
我有一个这样的集合:
[
{
"date": ISODate("2014-06-16T03:58:58.152Z"),
"min": 4,
"max": 25
},
{
"date": ISODate("2014-06-18T03:48:58.152Z"),
"min": 3,
"max": 8
},
{
"date": ISODate("2014-06-18T03:48:58.152Z"),
"min": 8,
"max": 12
}
]
我使用group
命令按天分组所有文档。
db.stats.group({
keyf: function (doc) {
var date = new Date(doc.date);
date.setHours(0, 0, 0, 0);
return { date: date };
},
reduce: function (curr, result) {
result.max = Math.max(curr.max, result.max || 0);
result.min = Math.min(curr.min, result.min || 0);
},
initial: {}
});
这给了我以下结果:
[
{
"date": ISODate("2014-06-16T21:00:00.000Z"),
"min": 4,
"max": 25
},
{
"date": ISODate("2014-06-18T21:00:00.000Z"),
"min": 3,
"max": 12
}
]
对我来说问题是,由于2014-06-17没有条目,我需要以某种方式创建一个min: 0 and max: 0
,所以结果应该是这样的:
[
{
"date": ISODate("2014-06-16T21:00:00.000Z"),
"min": 4,
"max": 25
},
{
"date": ISODate("2014-06-17T21:00:00.000Z"),
"min": 0,
"max": 0
},
{
"date": ISODate("2014-06-18T21:00:00.000Z"),
"min": 3,
"max": 12
}
]
如果我能以某种方式给group命令一个日期数组作为键可以工作。如果这可能在Mongo?
答案 0 :(得分:2)
如果我能以某种方式给group命令一个日期数组作为键可以工作。如果这可能在Mongo?
您不能group()
关于不存在的数据,因此您必须每天插入一些数据。
有效的方法是pre-aggregating data,以确保您的日期范围内每天都有样本。
对我来说问题是,由于2014-06-17没有参赛作品,我需要以某种方式创建一个min:0和max:0
鉴于您正在计算每日最小值/最大值,一种方法是利用MongoDB 2.6中的新$min
和$max
更新运算符,并将值插入到每日集合中。
由于您只希望每天获得混合/最大值,因此每日文档可能如下所示:
{
"date": "yyyy-mm-dd",
"min": 0,
"max": 0
}
注意:为了清楚起见,我选择将日期格式化为ISO8601-ish字符串,但是如果您愿意,也可以使用Date
字段。完整的BSON Date
将包含时间和时区信息,因此您需要确保截断您的查询/更新。
以下是mongo
shell中使用Moment.js
(方便日期操作)迭代一系列日期并添加任何缺失值的示例:
var nextDate = moment("2014-06-01");
var lastDate = moment("2014-07-31");
while (nextDate <= lastDate) {
db.daily.findAndModify({
query: {
date: nextDate.format("YYYY-MM-DD")
},
update: {
$max: { min: 0, max: 0 },
},
upsert: true
});
nextDate.add(1, 'day');
}
由于这是使用upsert
标志:
min
和max
字段值的$ max进行更新(即现有值将被保留)您可以使用相同的更新查询来维护每日最小值/最大值,因为插入了新数据(通过提供最小值/最大值而不是0
的当前值),或者计算每日最小值/最大值使用排序顺序的原始样本:
// Daily minimum for 2014-06-18 (assuming ticks are using standard `Date` fields)
db.ticks.find(
// query criteria
{ date: { $gte: ISODate("2014-06-18"), $lt: ISODate("2014-06-19") } },
// projection
{ min: 1, _id: 0 }
).sort({min: 1}).limit(1)
// Daily maximum for 2014-06-18
db.ticks.find(
// query criteria
{ date: { $gte: ISODate("2014-06-18"), $lt: ISODate("2014-06-19") } },
// projection
{ max: 1, _id: 0 }
).sort({max: -1}).limit(1)