Nếu nó chỉ là để hoàn thành mọi thứ trong khoảng thời gian 10 giây, bạn có thể làm một phép toán nhỏ và chạy điều này thông qua tổng hợp:
db.collection.aggregate([
{ "$group": {
"_id": {
"year": { "$year": "$created_at" },
"month":{ "$month": "$created_at" },
"day": { "$dayOfMonth": "$created_at" },
"hour": { "$hour": "$created_at" },
"minute": { "$minute": "$created_at" },
"second": { "$subtract": [
{ "$second": "$created_at" },
{ "$mod": [
{ "$second": "$created_at" },
10
]}
]}
},
"count": { "$sum" : 1 }
}}
])
Vì vậy, điều đó chia nhỏ mọi thứ thành khoảng thời gian 10 giây trong một phút mà chúng xảy ra với một phép toán mod 10 nhỏ.
Tôi nghĩ điều đó là hợp lý, và sẽ là người chạy nhanh nhất vì nó sử dụng tổng hợp. Nếu bạn thực sự cần trình tự của mình như được hiển thị là 10 giây chạy so với thời gian khớp ban đầu, thì bạn có thể thực hiện quy trình với mapReduce:
Người lập bản đồ đầu tiên:
var mapper = function () {
if ( this.created_at.getTime() > ( last_date + 10000 ) ) {
if ( last_date == 0 ) {
last_date = this.created_at.getTime();
} else {
last_date += 10000;
}
}
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
this.created_at
);
}
Vì vậy, điều này sẽ tạo ra các ngày trong khoảng thời gian 10 giây, bắt đầu với ngày đầu tiên và sau đó tăng khoảng thời gian mỗi khi phát hiện thứ gì đó nằm ngoài phạm vi
Bây giờ bạn cần một bộ giảm tốc:
var reducer = function (key, values) {
return values.length;
};
Rất đơn giản. Chỉ cần trả về độ dài của mảng được truyền vào.
Bởi vì mapReduce hoạt động theo cách của nó, bất kỳ thứ gì không có nhiều hơn một giá trị sẽ không được chuyển đến trình giảm bớt, vì vậy hãy làm sạch điều này bằng finalize:
var finalize = function (key, value) {
if ( typeof(value) == "object" ) {
value = 1;
}
return value;
};
Sau đó, chỉ cần chạy nó để nhận được kết quả. Lưu ý phần "phạm vi" chuyển một biến toàn cục sẽ được sử dụng trong trình liên kết:
db.collection.mapReduce(
mapper,
reducer,
{
"out": { "inline": 1 },
"scope": { "last_date": 0 },
"finalize": finalize
}
)
Mỗi cách tiếp cận có thể cho kết quả hơi khác nhau, nhưng đó là điểm chính. Nó phụ thuộc vào cái mà bạn thực sự muốn sử dụng.
Xem xét nhận xét của bạn, bạn có thể "kiểm tra" đầu ra từ một trong hai câu lệnh và "điền vào khoảng trống" theo chương trình như nó vốn có. Nói chung tôi thích tùy chọn đó hơn, nhưng đó không phải là chương trình của tôi và tôi không biết bạn đang cố truy xuất một chuỗi lớn như thế nào từ truy vấn này.
Ở phía máy chủ, bạn có thể vá "trình liên kết" để thực hiện một số việc như sau:
var mapper = function () {
if ( this.created_at.getTime() > ( last_date + 10000 ) ) {
if ( last_date == 0 ) {
last_date = this.created_at.getTime();
} else {
// Patching for empty blocks
var times = Math.floor(
( this.created_at.getTime() - last_date ) / 10000
);
if ( times > 1 ) {
for ( var i=1; i < times; i++ ) {
last_date += 10000;
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
0
);
}
}
// End patch
last_date += 10000;
}
}
emit(
{
start: new Date( last_date ),
end: new Date( last_date + 10000 )
},
this.created_at
);
}