2014-11-08 20 views
21

Tôi có một "tình trạng" bộ sưu tập như strcture này -Nhóm kết quả của 15 phút thời gian khoảng thời gian trong MongoDB

{ 
    _id: ObjectId("545a0b63b03dbcd1238b4567"), 
    status: 1004, 
    comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.", 
    created_at: ISODate("2014-11-05T11:34:59.804Z") 
}, 
{ 
    _id: ObjectId("545a0b66b03dbcd1238b4568"), 
    status: 1001, 
    comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.", 
    created_at: ISODate("2014-11-05T11:35:02.814Z") 
} 
.... 
.... 

tôi cần phải nhận được kết quả phân nhóm theo 15 phút khoảng từ bộ sưu tập đó.

+10

là một cái gì đó của họ trong câu trả lời với điều kiện không rõ ràng hoặc không áp dụng cho trường hợp của bạn? Lưu ý rằng nó vẫn không được chấp nhận. –

+3

Đừng bận tâm, anh ấy đã trả lời, tại sao lại bận tâm với việc chấp nhận câu trả lời. – nurgasemetey

Trả lời

70

Có một số cách để thực hiện việc này.

Đầu tiên là với Date Aggregation Operators, cho phép bạn phân tích các giá trị "ngày" trong tài liệu. Cụ thể đối với "nhóm" như mục đích chính:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "year": { "$year": "$created_at" }, 
      "dayOfYear": { "$dayOfYear": "$created_at" }, 
      "interval": { 
       "$subtract": [ 
        { "$minute": "$created_at" }, 
        { "$mod": [{ "$minute": "$created_at"}, 15] } 
       ] 
      } 
     }}, 
     "count": { "$sum": 1 } 
    }} 
]) 

Cách thứ hai là sử dụng một mẹo nhỏ khi một đối tượng ngày được trừ (hoặc hoạt động toán trực tiếp khác) từ một đối tượng ngày, sau đó kết quả là một giá trị số biểu diễn dấu thời gian epoch thời gian giữa hai đối tượng. Vì vậy, chỉ cần sử dụng ngày kỷ nguyên bạn nhận được đại diện mili giây epoch. Sau đó, sử dụng toán ngày cho khoảng thời gian:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "$subtract": [ 
       { "$subtract": [ "$current_date", new Date("1970-01-01") ] }, 
       { "$mod": [ 
        { "$subtract": [ "$current_date", new Date("1970-01-01") ] }, 
        1000 * 60 * 15 
       ]} 
      ] 
     }, 
     "count": { "$sum": 1 } 
    }} 
]) 

Vì vậy, nó phụ thuộc vào loại định dạng đầu ra bạn muốn cho khoảng thời gian nhóm. Cả hai cơ bản đại diện cho cùng một điều và có đủ dữ liệu để xây dựng lại như là một đối tượng "ngày" trong mã của bạn.

Bạn có thể đặt bất kỳ thứ gì khác bạn muốn vào phần "toán tử nhóm" sau khi nhóm _id. Tôi chỉ sử dụng ví dụ "đếm" cơ bản thay cho bất kỳ tuyên bố thực sự nào từ bản thân bạn về những gì bạn thực sự muốn làm.

+8

quá xấu tôi không thể chấp nhận cho anh ta - câu trả lời thực sự hữu ích! – Petrov

+2

tôi không thể đồng ý hơn @Petrov – aiapatag

+1

Không chỉ hữu ích mà còn được giải thích rất tốt. –

13

Tôi thích câu trả lời khác ở đây và chủ yếu cho việc sử dụng toán ngày thay vì toán tử ngày kết hợp trong khi hữu ích cũng có thể hơi mơ hồ.

Điều duy nhất tôi muốn thêm ở đây là bạn cũng có thể trả lại đối tượng Date từ khung tổng hợp theo phương pháp này trái ngược với dấu thời gian "số" làm kết quả. Nó chỉ là một chút toán học thêm trên cùng một nguyên tắc, sử dụng $add:

db.collection.aggregate([ 
    { "$group": { 
     "_id": { 
      "$add": [ 
       { "$subtract": [ 
        { "$subtract": [ "$current_date", new Date(0) ] }, 
        { "$mod": [ 
         { "$subtract": [ "$current_date", new Date(0) ] }, 
         1000 * 60 * 15 
        ]} 
       ] }, 
       new Date(0) 
      ] 
     }, 
     "count": { "$sum": 1 } 
    }} 
]) 

Các Date(0) contructs trong JavaScript ở đây đại diện cho "kỷ nguyên" cùng ngày trong một hình thức ngắn hơn, như 0 millisecond từ thời đại là thời đại. Nhưng điểm chính là khi "bổ sung" vào đối tượng ngày BSON khác được thực hiện với một số nhận dạng, thì nghịch đảo của điều kiện được mô tả là đúng và kết quả cuối cùng thực sự là một Date.

Tất cả trình điều khiển sẽ trả về kiểu gốc Date cho ngôn ngữ của họ theo cách tiếp cận này.

6

Đẹp hơn một chút đối với mongo db.version() < 3.0

db.collection.aggregate([ 
    {$match: {created_at:{$exists:1}}}, 
    {$group: { 
     _id: {$add:[ 
      {$dayOfYear: "$created_at" }, 
      {$multiply: [{$year: "$created_at"}, 1000]} 
     ]}, 
     count: {$sum: 1 } 
    }}, 
    {$sort:{_id:-1}} 
]) 
2

Một cách hữu ích:

db.collection.aggregate([ 
    {$group: { 
    _id: { 
     overallTime: { 
     $dateToString: { format: "%Y-%m-%dT%H", date: "$created_at" } 
     }, 
     interval: { $trunc: { $divide: [{ $minute: "$created_at" }, 15 ]}} 
    }, 
    }}, 
]) 

Và dễ dàng hơn cho phút, giờ, ngày khoảng:

var format = "%Y-%m-%dT%H:%M"; // 1 min 
var format = "%Y-%m-%dT%H"; // 1 hour 
var format = "%Y-%m-%d"; // 1 day 

db.collection.aggregate([ 
    {$group: { 
    _id: { $dateToString: { format: format, date: "$created_at" } }, 
    }}, 
]) 
Các vấn đề liên quan