2014-10-16 68 views
8

我有一个产品集合与下列文件:MongoDB的aggreagte填充缺失的天

{ "_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") } 

我想提请白天描述产品的计数的图表,所以我使用MongoDB的聚合框架一天来算产品组:

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}} 
     ]) 

在蒙戈壳的结果是:

{ 
    "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 
} 

当然,没有产品的一些天,并使用上述结果设置图表看起来是这样的:

enter image description here

但所需的图表看起来应该是这样:

desired output

所以,问题是:哪有我在count = 0的结果集中添加了错过的日期(例如最近30天的时间)?这意味着,所需的结果集应该是这样的:

{ 
    "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 
} 

回答

6

使用聚合完全处理这个问题是一个痛苦。
但它可以达到。
(MongoDB的V2.6 +所需)

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 
      } 
     } ]); 

我想填补结束应用程序是这样的,供大家参考缺少的一部分:

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

这个问题可以更好地解释。尽管我在第一部分和第二部分代码中都看到了逻辑,但很多人会对这些代码如何一起工作感到困惑。 – 2017-04-26 19:40:39

2

好吧,首先:不存在的价值进行评估,以null(大致翻译为“虚无缥缈”,“一无所有”,“不存在” ),它不等于0,这是一个明确定义的值。例如,对于0到42之间的差异,MongoDB没有语义理解。那么MongoDB应该如何决定在哪一天(哪一个mongo也没有语义理解)假设哪一个值?

基本上,你有两个选择:每天保存一个0,当没有值记录时,或者你在你创建一个图表的时候在你的应用程序中迭代,每天发出0没有值作为替代品存在。我'建议做前者,因为这将使得使用聚合框架成为可能。

+0

“空” 是语义上更像是一个[SQL](https://en.wikipedia.org/wiki/Null_(SQL))或[JSON](http://json.org/)'null',而不是一个指针NULL。 – Soren 2014-10-18 16:34:50

+0

其中两者都是什么序列化的表示? ;) – 2014-10-18 16:38:24

+0

没有任何东西 - 它们是空的而不是任何序列化的值,但是它们本身超出正常的价值范围 - 存在细微的语义差异。 – Soren 2014-10-18 16:42:18