這是一個棘手的問題來了解,但有一個主要問題的「聚合框架」這裏主要是你的「活動」根據目前的狀態生活在幾個不同的時間間隔。
這意味着它始終存在一個「開始」和「完成」間隔以及可能被視爲「正在執行」的「幾個」間隔。
聚合框架無法真正做到這一點。但是你可以用MapReduce的做到這一點:
db.test.mapReduce(
function() {
// Work out time values
var finished = this.timestamp.valueOf() + this.duration,
finishedInterval = finished -
(finished % (1000 * 60 * 10)),
interval = this.timestamp.valueOf() -
(this.timestamp.valueOf() % (1000 * 60 * 10));
// Emit initialized
emit(
{
"year": new Date(interval).getUTCFullYear(),
"month": new Date(interval).getUTCMonth()+1,
"day": new Date(interval).getUTCDate(),
"hour": new Date(interval).getUTCHours(),
"minute": new Date(interval).getUTCMinutes()
},
{
"Initialized": 1,
"InExecution": 0,
"Finshed": 0
}
);
// Emit finished
emit(
{
"year": new Date(finishedInterval).getUTCFullYear(),
"month": new Date(finishedInterval).getUTCMonth()+1,
"day": new Date(finishedInterval).getUTCDate(),
"hour": new Date(finishedInterval).getUTCHours(),
"minute": new Date(finsihedInterval).getUTCMinutes()
},
{
"Initialized": 0,
"InExecution": 0,
"Finshed": 1
}
);
// Emit In execution for every 10 minute interval until finished
if ((interval + (1000 * 60 * 10)) < finishedInterval) {
for (var x = interval; x<finishedInterval; x+= (1000 * 60 * 10)) {
emit(
{
"year": new Date(x).getUTCFullYear(),
"month": new Date(x).getUTCMonth()+1,
"day": new Date(x).getUTCDate(),
"hour": new Date(x).getUTCHours(),
"minute": new Date(x).getUTCMinutes()
},
{
"Initialized": 0,
"InExecution": 1,
"Finshed": 0
}
);
}
}
},
function(key,values) {
var result = { "Initialized": 0, "InExecution": 0, "Finshed": 0 };
values.forEach(function(value) {
Object.keys(value).forEach(function(key) {
result[key] += value[key];
});
});
return result;
},
{
"out": { "inline": 1 },
"query": { "timestamp": { "$gte": new Date("2015-04-27T12:00:00Z") } }
}
)
正如你所看到的,大部分工作在映射完成。這基本上可以確定任務「開始」和「結束」的時間間隔,併爲此發出適當的數據。
然後,當然通過在任務的「開始」間隔工作,每10分鐘發出一個「執行中」計數,而該值小於任務的「結束」間隔。
減速器只是將每個間隔的所有發射計數加起來並加起來。所以這是一個非常簡單的操作。
的地圖和減少的邏輯是合理的,但第一個查詢時間之前開始在工作「finshing」或「執行」是有可能會查詢選擇邏輯的一個問題。
爲了做到這一點,您需要修復該查詢選擇以考慮該問題,並且由於您不存儲「完成」時間,因此需要計算該時間,這意味着查詢中的JavaScript評估與:
{
"out": { "inline": 1 },
"query": {
"$where": function() {
return (this.timestamp >= new Date("2015-04-27T12:00:00Z") ||
new Date(this.timestamp.valueOf() + this.duration) >=
new Date("2015-04-27T12:00:00Z"))
}
}
}
這個選項在當前查詢的開始時間或結束時仍然運行。
這不是偉大的,因爲它掃描的集合,這樣它會更好,包括「finshed」作爲您的數據值,以使查詢選擇更容易:
{
"out": { "inline": 1 },
"query": {
"$or": [
{ "timestamp": { "$gte": new Date("2015-04-27T12:00:00Z") } },
{ "finished": { "$gte": new Date("2015-04-27T12:00:00Z") } }
]
}
}
,可以使用「指數」和要快得多。
作爲最後的事情,仍然會有,因爲在這兩種形式的「成品」這裏「之前」的「時間戳」過濾器值發射值意味着,在該時間之前啓動的任務。由於相同的原因,在查詢條件和邏輯上放置「結束」時間也是一個好主意。
對於這個再次改變的選項框以包括「範圍」瓦爾在執行邏輯中使用,並也增加了「查詢」的條件:
{
"out": { "inline": 1 },
"query": {
"$or": [
{
"timestamp": {
"$gte": new Date("2015-04-27T12:00:00Z"),
"$lt": new Date("2015-04-28T12:00:00Z")
}
},
{
"finished": {
"$gte": new Date("2015-04-27T12:00:00Z"),
"$lt": new Date("2015-04-28T12:00:00Z")
}
}
]
},
"scope": {
"start": new Date("2015-04-27T12:00:00Z"),
"finsh": new Date("2015-04-28T12:00:00Z")
}
}
然後圍繞每個發射添加的條件下,第一對於開始的地方 「間隔」 大於 「開始」:
// Emit initialized
if (interval >= start.valueOf()) {
emit(
而且finsihed其中 「finishedInterval」 小於 「完成」:
// Emit finished
if (finishedInterval <= finish.valueOf()) {
emit(
然後限制上的「執行力」,以及環路:
// Emit In execution for every 10 minute interval until finished
if ((interval + (1000 * 60 * 10)) < finishedInterval) {
for (var x = interval; ((x<finishedInterval) && (x<finish.valueOf())); x+= (1000 * 60 * 10)) {
if (x > start.valueOf()) {
emit(
這就給了你一個乾淨的起點和終點,同時保持所有可能的結果中列出的統計信息。
如果你學習我給你應該認識到,這些結果是不一樣的答案的內容。 「完成」只是在特定時期開始和完成的工作。對於「執行中」也是如此,因爲它只報告該時期的工作正在執行,而後者僅在該時期執行。如果任何一種類型「跨越邊界」(並且可能是毫秒級的問題),那麼它將不會被拾取。這就是爲什麼選擇mapReduce作爲答案的原因,我花時間解釋了這些問題。 –