在查找/聚合之后填写具有默认值的文档

all*_*cth 2 mongodb

我有一个集合:

{ "name" : "A", "value" : 1, "date" : ISODate("2014-01-01T00:00:00.000Z") }
{ "name" : "B", "value" : 7, "date" : ISODate("2014-01-01T00:00:00.000Z") }
{ "name" : "A", "value" : 3, "date" : ISODate("2014-01-02T00:00:00.000Z") }
{ "name" : "B", "value" : 8, "date" : ISODate("2014-01-02T00:00:00.000Z") }
{ "name" : "B", "value" : 8, "date" : ISODate("2014-01-03T00:00:00.000Z") }
{ "name" : "A", "value" : 5, "date" : ISODate("2014-01-04T00:00:00.000Z") }
{ "name" : "A", "value" : 4, "date" : ISODate("2014-01-05T00:00:00.000Z") }
Run Code Online (Sandbox Code Playgroud)

2014年1月3日的A文档不可用.当我在A上进行查找/聚合时,我希望文档在我的结果集中显示为默认值(或更好,值与上一个日期相同).例如:

{ "name" : "A", "value" : 1, "date" : ISODate("2014-01-01T00:00:00.000Z") }
{ "name" : "A", "value" : 3, "date" : ISODate("2014-01-02T00:00:00.000Z") }
{ "name" : "A", "value" : 3 (or default value -1), "date" : ISODate("2014-01-03T00:00:00.000Z") }
{ "name" : "A", "value" : 5, "date" : ISODate("2014-01-04T00:00:00.000Z") }
{ "name" : "A", "value" : 4, "date" : ISODate("2014-01-05T00:00:00.000Z") }
Run Code Online (Sandbox Code Playgroud)

如何才能做到这一点?

Asy*_*sky 5

你为了需要有一件事是能够做到这一点的聚合框架是您希望您的报告涵盖的日期的数组.例如,对于您显示的输入,您可能有一个数组:

days = [ ISODate("2014-01-01T00:00:00Z"), ISODate("2014-01-02T00:00:00Z"), 
         ISODate("2014-01-03T00:00:00Z"), ISODate("2014-01-04T00:00:00Z"), 
         ISODate("2014-01-05T00:00:00Z"), ISODate("2014-01-06T00:00:00Z") ];
Run Code Online (Sandbox Code Playgroud)

表示你希望这六天中的每一天都有代表.

以下是您要运行的聚合:

db.coll.aggregate( [
     {$group : {_id:{name:"$name",date:"$date"},value:{$sum:"$value"}}},
     {$group : {_id:"$_id.name", days:{$addToSet:"$_id.date"},docs:{$push:"$$ROOT"}}},
     {$project : {missingDays:{$setDifference:[days,"$days"]},docs:1}},
     {$unwind : "$missingDays"},
     {$unwind : "$docs"},
     {$group : { 
          _id:"$_id", 
          days:{$addToSet:{date:"$docs._id.date",value:"$docs.value"}},
          missingDays:{$addToSet:{date:"$missingDays",value:{$literal:0}}}
     } }, 
     {$project : {_id:0, name:"$_id", date:{$setUnion:["$days","$missingDays"]}}},
     {$unwind : "$date"},
     {$sort : {date:1,name:1}}
] )
Run Code Online (Sandbox Code Playgroud)

在您的样本输入上,如上定义的日期输出:

{ "name" : "A", "date" : { "date" : ISODate("2014-01-01T00:00:00Z"), "value" : 1 } }
{ "name" : "A", "date" : { "date" : ISODate("2014-01-02T00:00:00Z"), "value" : 3 } }
{ "name" : "A", "date" : { "date" : ISODate("2014-01-03T00:00:00Z"), "value" : 0 } }
{ "name" : "A", "date" : { "date" : ISODate("2014-01-04T00:00:00Z"), "value" : 5 } }
{ "name" : "A", "date" : { "date" : ISODate("2014-01-05T00:00:00Z"), "value" : 4 } }
{ "name" : "A", "date" : { "date" : ISODate("2014-01-06T00:00:00Z"), "value" : 0 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-01T00:00:00Z"), "value" : 7 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-02T00:00:00Z"), "value" : 8 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-03T00:00:00Z"), "value" : 8 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-04T00:00:00Z"), "value" : 0 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-05T00:00:00Z"), "value" : 0 } }
{ "name" : "B", "date" : { "date" : ISODate("2014-01-06T00:00:00Z"), "value" : 0 } }
Run Code Online (Sandbox Code Playgroud)

在您的情况下,可能不需要第一个小组阶段 - 如果有多个文档具有相同的名称和日期,那么就是这种情况,在这种情况下,您要为它们添加值.第二个$ group和$ project阶段计算出每个名称的天数与您想要覆盖的天数之间的差异,创建missingDays将在下一$group阶段获得值0的值.该组阶段为每个name日期数组创建具有数据和缺少日期数组的日期.它$project以类似的方式构造它们,以便下一个阶段可以使用$setUnion运算符创建它们的并集.之后剩下的就是$unwind日期数组,并按照您想要的方式对其进行排序.