我有很多像这样的文档:
{
"_id" : ObjectId("54a94200aa76d3db6cd51977"),
"URL" : "http://...",
"Statistics" : [
{
"Date" : ISODate("2010-05-18T18:07:29.000+0000"),
"Clicks" : NumberInt(250),
},
{
"Date" : ISODate("2010-05-21T12:06:41.000+0000"),
"Clicks" : NumberInt(165),
},
{
"Date" : ISODate("2010-05-30T08:37:50.000+0000"),
"Clicks" : NumberInt(263),
}
]
}
我的查询如下:
db.clicks.aggregate([
{ $match : 'Statistics.Date' : { $gte: new Date("2010-05-18T00:00:00.000Z"), $lte: new Date("2010-05-18T23:59:59.999Z") } },
{ $unwind' => '$Statistics' },
{ $group : { _id : { year : { $year : '$Statistics.Date' }, month : { $month : '$Statistics.Date' }, day : { $dayOfMonth : '$Statistics.Date' } }, Clicks : { $sum : '$Statistics.Clicks' } },
{ $sort : { _id : 1 } }
])
当我试图总结特定日期的点击量时,它会给我所有的日期,而不是只有一个。我做错了什么?提前谢谢。
编辑1:由于该集合中有超过80000个文档,我无法在$match
之前执行$unwind
。此外,担心这不是一个好主意,因为这会使查询速度慢于必要的速度。其中大量的文档和数据是我必须使用$sum
的原因。我上面制作的文档只是一个例子,只有结构与我的项目相同。
上面的查询给了我这样的smth:
{
"_id" : [
{
"year" : 2010,
"month" : 5,
"day" : 18
}
],
"Clicks" : 250
},
{
"_id" : [
{
"year" : 2010,
"month" : 4,
"day" : 21
}
],
"Clicks" : 165
},
{
"_id" : [
{
"year" : 2010,
"month" : 5,
"day" : 30
}
],
"Clicks" : 263
}
如果我不使用$group
,我也必须使用$limit
,因为查询将超过16MB,否则:
db.clicks.aggregate([
{ $match : 'Statistics.Date' : { $gte: new Date("2010-05-18T00:00:00.000Z"), $lte: new Date("2010-05-18T23:59:59.999Z") } },
{ $unwind' : '$Statistics' },
{ $limit : 1 }
])
这个结果:
{
"_id" : ObjectId("54a94200aa76d3db6cd51977"),
"URL" : "http://...",
"Statistics" : {
"Date" : {
"sec" : 1274166878,
"usec" : 0
},
"Clicks" : 250
}
}
由于性能原因,我不得不使用$group
,不使用它不是一种选择。
正如我在PHP中所做的那样,我提到的文档、查询和结果中可能存在一些错误。希望这不会成为问题。我还没有弄清楚是什么导致了我的问题。有人能帮我吗?
编辑2:由于这似乎是一个无法解决的性能问题,我正在将"Statistics"数组中的所有数据迁移到自己的集合中。感谢任何人的帮助。
您需要运行$match
两次,分别在之前和之后运行$unwind
:
db.clicks.aggregate([
{ $match : { 'Statistics.Date' : {
$gte: new ISODate("2010-05-18T00:00:00.000Z"),
$lte: new ISODate("2010-05-18T23:59:59.999Z") } } },
{ $unwind: '$Statistics' },
{ $match : { 'Statistics.Date' : {
$gte: new ISODate("2010-05-18T00:00:00.000Z"),
$lte: new ISODate("2010-05-18T23:59:59.999Z") } } },
{ $group : {
_id : { year : { $year : '$Statistics.Date' },
month : { $month : '$Statistics.Date' },
day : { $dayOfMonth : '$Statistics.Date' } },
Clicks : { $sum : '$Statistics.Clicks' } } },
{ $sort : { _id : 1 } }
])
第一个$match
用于选择在正确日期范围内具有至少一个Statistics
元素的文档。第二个用于过滤掉那些文档中不在正确日期范围内的其他Statistics
元素。
事情可能已经解决,但为寻求帮助的人发布答案
{ $match : 'Statistics.Date' : { $gte: new Date("2010-05-18T00:00:00.000Z"),
enter code here$lte: new Date("2010-05-18T23:59:59.999Z") } }
此匹配将筛选主要文档。您想要的是过滤Statistics数组中的文档
现在,经过$match
筛选的文档将包含完整的Statistics数组。过滤后展开可能会有Statistics的子文档,其同级文档(同一数组中的文档(已通过$match
条件。
注:简单查找投影:
db.col_name.find({},{"Statistics.$":1})
也会过滤数组,但是聚合中的$project
对筛选文档数组没有帮助。