2014-10-16 28 views
8

Tôi có một bộ sưu tập sản phẩm với các tài liệu sau:MongoDB aggreagte điền thiếu ngày

{ "_id" : 1, "item" : "abc", created: ISODate("2014-10-01T08:12:00Z") } 
{ "_id" : 2, "item" : "jkl", created: ISODate("2014-10-02T09:13:00Z") } 
{ "_id" : 3, "item" : "hjk", created: ISODate("2014-10-02T09:18:00Z") } 
{ "_id" : 4, "item" : "sdf", created: ISODate("2014-10-07T09:14:00Z") } 
{ "_id" : 5, "item" : "xyz", created: ISODate("2014-10-15T09:15:00Z") } 
{ "_id" : 6, "item" : "iop", created: ISODate("2014-10-16T09:15:00Z") } 

Tôi muốn vẽ một biểu đồ mô tả số lượng sản phẩm theo ngày, vì vậy tôi sử dụng khuôn khổ hợp MongoDB để đếm nhóm sản phẩm theo ngày:

var proj1 = { 
     "$project": { 
      "created": 1, 
      "_id": 0, 
      "h": {"$hour": "$created"}, 
      "m": {"$minute": "$created"}, 
      "s": {"$second": "$created"}, 
      "ml": {"$millisecond": "$created"} 
     } 
    }; 

    var proj2 = { 
     "$project": { 
      "created": { 
       "$subtract": [ 
        "$created", { 
         "$add": [ 
          "$ml", 
          {"$multiply": ["$s", 1000]}, 
          {"$multiply": ["$m", 60, 1000]}, 
          {"$multiply": ["$h", 60, 60, 1000]} 
         ] 
        }] 
      } 
     } 
    }; 

    db.product.aggregate([ 
      proj1, 
      proj2, 
      {$group: { 
       _id: "$created", 
       count: {$sum: 1} 
      }}, 
      {$sort: {_id: 1}} 
     ]) 

kết quả trong vỏ Mongo là:

{ 
    "result" : [ 
     { 
      "_id" : ISODate("2014-10-01T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-10-02T00:00:00.000Z"), 
      "count" : 2 
     }, 
     { 
      "_id" : ISODate("2014-10-07T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-10-15T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-10-16T00:00:00.000Z"), 
      "count" : 1 
     } 
    ], 
    "ok" : 1 
} 

Tất nhiên, không có sản phẩm vài ngày và biểu đồ bằng cách sử dụng kết quả thiết lập ở trên trông như thế này:

enter image description here

Nhưng bảng xếp hạng mong muốn sẽ giống như thế này:

desired output

Vì vậy, câu hỏi là: thế nào có thể Tôi thêm ngày mất tích (ví dụ 30 ngày qua) vào tập hợp kết quả với count = 0? Điều đó có nghĩa, kết quả thiết lập mong muốn nên trông như thế này:

{ 
    "result" : [ 
     { 
      "_id" : ISODate("2014-09-16T00:00:00.000Z"), 
      "count" : 0 
     }, 
     { 
      "_id" : ISODate("2014-09-17T00:00:00.000Z"), 
      "count" : 0 
     }, 
     ...    
     { 
      "_id" : ISODate("2014-10-01T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-10-02T00:00:00.000Z"), 
      "count" : 2 
     }, 
     { 
      "_id" : ISODate("2014-10-03T00:00:00.000Z"), 
      "count" : 0 
     }, 
     ... 
     { 
      "_id" : ISODate("2014-10-07T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-09-08T00:00:00.000Z"), 
      "count" : 0 
     }, 
     ... 
     { 
      "_id" : ISODate("2014-10-15T00:00:00.000Z"), 
      "count" : 1 
     }, 
     { 
      "_id" : ISODate("2014-10-16T00:00:00.000Z"), 
      "count" : 1 
     }, 
     // also, add some extra days 
     { 
      "_id" : ISODate("2014-10-17T00:00:00.000Z"), 
      "count" : 0 
     }, 
     { 
      "_id" : ISODate("2014-10-10T00:00:00.000Z"), 
      "count" : 0 
     } 
    ], 
    "ok" : 1 
} 

Trả lời

6

Sử dụng tổng hợp để xử lý câu hỏi này hoàn toàn là một nỗi đau.
Nhưng nó có thể đạt được.
(MongoDB v2.6 + yêu cầu)

var proj1 = { 
    "$project" : { 
     "created" : 1, 
     "_id" : 0, 
     "h" : { 
      "$hour" : "$created" 
     }, 
     "m" : { 
      "$minute" : "$created" 
     }, 
     "s" : { 
      "$second" : "$created" 
     }, 
     "ml" : { 
      "$millisecond" : "$created" 
     } 
    } 
}; 

var proj2 = { 
    "$project" : { 
     "created" : { 
      "$subtract" : [ "$created", { 
       "$add" : [ "$ml", { 
        "$multiply" : [ "$s", 1000 ] 
       }, { 
        "$multiply" : [ "$m", 60, 1000 ] 
       }, { 
        "$multiply" : [ "$h", 60, 60, 1000 ] 
       } ] 
      } ] 
     } 
    } 
}; 

var group1 = { 
     $group : { 
      _id : "$created", 
      count : { 
       $sum : 1 
      } 
     } 
    }; 

var group2 = { 
     $group : { 
      _id : 0, 
      origin : { 
       $push : "$$ROOT" 
      }, 
      maxDate : { 
       $max : "$_id" 
      } 
     } 
}; 

var step = 24 * 60 * 60 * 1000; // milliseconds of one day 

var project3 = { 
    $project : { 
     origin : 1, 
     extents : { 
      $map : { 
       "input" : [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29], 
       "as" : "e", 
       "in" : { 
        _id : { 
         $subtract : [ "$maxDate", { 
          $multiply : [ step, "$$e"] 
         }] 
        }, 
        count : { 
         $add : [0] 
        } 
       } 
      } 
     } 
    } 
}; 

var project4 = { 
     $project : { 
      _id : 0, 
      values : { 
       $setUnion : [ "$origin", "$extents"] 
      } 
     } 
}; 

var unwind1 = { 
     $unwind : "$values" 
}; 

var group3 = { 
     $group : { 
      _id : "$values._id", 
      count : { 
       $max : "$values.count" 
      } 
     } 
}; 

db.product.aggregate([ proj1, proj2, group1, group2, project3, project4, 
     unwind1, group3, { 
      $sort : { 
       _id : 1 
      } 
     } ]); 

Tôi muốn để điền vào phần còn thiếu một cái gì đó ở cuối ứng dụng như thế này để bạn tham khảo:

function sortResult(x, y) { 
    var t1 = x._id.getTime(); 
    var t2 = y._id.getTime(); 
    if (t1 < t2) { 
     return -1; 
    } else if (t1 == t2) { 
     return 0; 
    } else { 
     return 1; 
    } 
} 

var result = db.product.aggregate(); 

var endDateMilliseconds = result[result.length - 1]._id.getTime(); 
var step = 24 * 60 * 60 * 1000; // milliseconds of one day 

var map = {}; 
for (var i in result) { 
    map[ result[i]._id.getTime() ] = result[i]; 
} 

for (var ms = endDateMilliseconds, x = 1; x < 30; x++) { 
    ms -= step; 
    if (! (ms in map)) { 
     map[ms] = {_id : new Date(ms), count : 0}; 
    } 
} 

var finalResult = []; 
for (var x in map) { 
    finalResult.push(map[x]); 
} 
finalResult.sort(sortResult); 
printjson(finalResult); 
+1

Câu hỏi này có thể được giải thích rõ hơn. Trong khi tôi thấy logic trong mỗi đoạn mã đầu tiên và thứ hai, nhiều người sẽ bị nhầm lẫn với cách chúng hoạt động cùng nhau. –

2

Ok, trước hết là: giá trị không tồn tại được đánh giá để null (nôm na là "nada", "không có gì", "không có"), không bằng 0, là giá trị được xác định rõ.

MongoDB không có sự hiểu biết ngữ nghĩa về sự khác biệt giữa 0 và 42, ví dụ. Vậy MongoDB nên quyết định giá trị nào giả định cho một ngày trong thời gian đó (trong đó Mongo cũng không có sự hiểu biết ngữ nghĩa)? Về cơ bản, bạn có hai lựa chọn: lưu 0 cho mỗi ngày khi không có giá trị nào để ghi hoặc bạn lặp lại trong ứng dụng của mình trong những ngày bạn muốn tạo biểu đồ và phát hành 0 cho mỗi ngày không có giá trị tồn tại như là một thay thế. Id 'đề xuất làm việc trước đây, vì điều đó sẽ làm cho nó có thể sử dụng khung công tác tổng hợp.

+0

Các "Null" là sematically giống như một [SQL] (https://en.wikipedia.org/wiki/Null_ (SQL)) hoặc [JSON] (http://json.org/) 'null' hơn một con trỏ' NULL.' – Soren

+0

cả hai được đại diện theo thứ tự của những gì? ;) –

+0

Không có gì - chúng là giá trị rỗng và không được tuần tự hóa của bất kỳ thứ gì, nhưng giá trị của chúng nằm ngoài phạm vi giá trị bình thường - có sự khác biệt ngữ nghĩa tinh tế. – Soren

Các vấn đề liên quan