我有很多像这样的文件:
{
"_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:
由于该集合中有> 80.000个文档,因此我无法在$unwind
之前执行$match
。此外,这不是一个好主意,因为这会使查询慢于必要。
其中包含大量文档和数据是我必须使用$sum
的原因。我上面提到的文件只是一个例子,只有结构与我的项目相同。
上面的查询让我回想起这样的事情:
{
"_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: 由于这似乎是一个无法解决的性能问题,因此我将从“统计数据”中迁移所有数据。数组到自己的集合中。感谢任何人的帮助。
答案 0 :(得分:0)
您需要在$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
元素。
答案 1 :(得分:0)
事情可能已经解决,但是为那些从这个问题寻求帮助的人发布答案
{ $match : 'Statistics.Date' : { $gte: new Date("2010-05-18T00:00:00.000Z"),
enter code here$lte: new Date("2010-05-18T23:59:59.999Z") } }
此匹配将过滤主文档。你想要的是过滤统计数组中的文档
现在,由$match
过滤的文档将包含完整的Statistic数组。过滤后展开可能包含Statistic的子文档,其兄弟文档(同一数组中的文档)已通过$match
条件。
注意:简单查找投影:
db.col_name.find({},{"Statistics.$":1})
也会过滤数组 聚合中的$project
无助于过滤文档数组。