2014-07-27 39 views
0

我使用Mongo作爲tick數據庫,我週期性地將數據與時間戳放在一起。稍後我使用這些數據來查詢有關係統的統計信息。Mongo組命令與丟失鍵

我有這樣一個集合:

[ 
    { 
    "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年6月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 
    } 
] 

如果我可以以某種方式給組命令一組日期作爲鍵這可以工作。如果這可能在Mongo中?

+0

我有類似的問題,看看這裏:http://stackoverflow.com/questions/25039406/skipped-count-0-in-aggregate-function?noredirect=1#comment38963506_25039406 – knowbody

回答

2

如果我可以以某種方式給組命令一組日期作爲鍵,這可以工作。如果這可能在Mongo中?

對於不存在的數據,您不能group(),所以您將不得不爲每一天插入一些數據。

爲了確保您的日期範圍內每天都有樣品,有效採用的方法是pre-aggregating data

,我的問題是,因爲是在2014年6月17日沒有條目我需要以某種方式創建一個與分:0和max:0

鑑於你計算每天分鐘/ max,一種方法是利用MongoDB 2.6中的新的$min$max更新運算符以及每日收集的upsert值。

既然你只希望有混合/每天最大值,每天文檔可能看起來像:

{ 
    "date": "yyyy-mm-dd", 
    "min": 0, 
    "max": 0 
} 

注:我選擇日期格式爲澄清在ISO8601上下的字符串這個例子,但你也可以使用Date字段,如果你願意。完整的BSON Date將包含時間和時區信息,因此您需要確保正確截斷查詢/更新。

下面是使用Moment.js(爲方便日期操作)來迭代日期範圍並添加任何缺少的值在mongo殼的一個示例:

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標誌:

  • 不存在的每日文檔將插入默認的最小值/最大值0
  • 確實存在的每日文檔將使用它們的前綴$ max是minmax字段值(即,現有值將被保留)

你可以使用相同的更新查詢,以保持你的日常最小值/最大值作爲新的數據插入(由最小/最大,而不是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) 
+0

這工作,如果我每天只查詢,但是我的數據有「縮放級別」。你可以看看一分鐘的深度。猜猜我最好的選擇是在查詢後做一些數據處理。 –

+0

@RobFox:僅供參考,鏈接的[預彙總報告](http://docs.mongodb.org/ecosystem/use-cases/pre-aggregated-reports/)頁面包括一些典型的不同時間序列數據的方法粒度。如果預先彙總的方法不適合您的用例,您將不得不在應用程序代碼中進行一些數據處理,以便在填寫數據時填補空白。 – Stennie