事实证明$ project不支持聚合中的$ elemMatch。在3.2中,他们引入了filter等,这似乎并没有解决我的问题。
让我解释一下我正在尝试做什么,假设我在数据库中有以下文件。
db.test.insert(
{
"ad_account_id": 150,
"internal_id": 1,
"daily": [{
"timestamp": "2016-12-01",
"impressions": 5
}, {
"timestamp": "2016-12-06",
"impressions": 7
}]
})
db.test.insert(
{
"ad_account_id": 150,
"internal_id": 2,
"daily": [{
"timestamp": "2016-12-03",
"impressions": 6
}]
})
db.test.insert({
"ad_account_id": 150,
"internal_id": 3,
"daily": []
})
db.test.insert({
"ad_account_id": 16,
"internal_id": 3,
"daily": []
})
现在假设用户查询ad_account_id:150,并按开始和结束日期范围过滤为“2016-12-01”至“2016-12-02”。
我的聚合查询如下所示(跳过排序,限制等)
db.getCollection('test').aggregate({
"$match" : {
"ad_account_id" : 150,
"daily" : {
"$elemMatch" : {
"timestamp" : {
"$lte" : "2016-12-02",
"$gte" : "2016-12-01"
}
}
}
}
},
{
"$unwind" : "$daily"
},
{
"$match" : {
"daily.timestamp" : {
"$lte" : "2016-12-02",
"$gte" : "2016-12-01"
}
}
},
{
"$group" : {
"impressions" : {
"$sum" : "$daily.impressions"
},
"ad_account_id" : {
"$first" : "$ad_account_id"
},
"_id" : "$internal_id"
}
},
{
"$project" : {
"impressions" : 1,
"ga_transactions" : 1,
"ad_account_id" : 1
}
}
);
当前结果
{ "_id" : 1, "impressions" : 5, "ad_account_id" : 150 }
在我们的本地开发中,它最初似乎没问题。即使有一百万份文件,查询也很快,我们很高兴。
但是我们很快意识到了我们的用例,即使每天的数据不在开始日期和结束日期之间,我们也需要显示行。其中的印象数等可以用0表示,但必须要显示它们。
所以我们想要的期望的结果就是这个
{ "_id" : 1, "impressions" : 5, "ad_account_id" : 150 }
{ "_id" : 2, "impressions" : 0, "ad_account_id" : 150 }
{ "_id" : 3, "impressions" : 0, "ad_account_id" : 150 }
在过去的几个小时里,我一直在努力解决这个问题,因为我似乎无法在单个mongo查询中得到这个。我以为我会将我的匹配限制为广告帐户ID,然后执行$项目,如果该数据范围之间没有数据,我只会添加一个示例条目到每日,并将起始数据作为时间戳这样的事情。
{
"ad_account_id": 150,
"internal_id": 3,
"daily": [{timestamp: "2016-02-01"}]
)
但不幸的是我无法让这个工作,因为在$ project中你无法做到$ elemMatch。像$ filter等新东西似乎没有解决我的问题。
我也尝试过工会,我认为它几乎也存在。但是这给了我一个错误“”FieldPath'2016-12-01'不以$“开头。
您认为最好的方法是什么?
答案 0 :(得分:1)
好吧,花了几个小时的时间,并有一个尤里卡时刻。结果我离解决方案太远了。
db.getCollection('test').aggregate(
{
"$match" : {
"ad_account_id" : 150
}
},
{ "$project": {
"ad_account_id": 1,
"internal_id": 1,
"daily": {
"$setUnion": [
{ "$map": {
"input": "$daily",
"as": "day",
"in": {
"$cond": [
{ "$and": [
{ "$gte": [ "$$day.timestamp", "2016-12-01" ] },
{ "$lte": [ "$$day.timestamp", "2016-12-02" ] }
]},
"$$day",
false
]
}
}},
[{"$literal": {"timestamp": "2016-12-01" } }]
]
}
}},
{
"$unwind" : "$daily"
},
{
"$group" : {
"impressions" : {
"$sum" : "$daily.impressions"
},
"ad_account_id" : {
... "$first" : "$ad_account_id"
... },
"_id" : "$internal_id"
}
},
{
"$project" : {
"impressions" : 1,
"ad_account_id" : 1
}
}
);
对于想要这个想法的人,我将"daily_mod": { $addToSet: "$daily" }
添加到最后一个$ group阶段,并将其添加到上一个项目"daily_mod": 1
。
这将真正帮助您了解发生的情况并提供输出 - :
{ "_id" : 3, "impressions" : 0, "ad_account_id" : 150, "daily_mod" : [ { "timestamp" : "2016-12-01" } ] }
{ "_id" : 2, "impressions" : 0, "ad_account_id" : 150, "daily_mod" : [ false, { "timestamp" : "2016-12-01" } ] }
{ "_id" : 1, "impressions" : 5, "ad_account_id" : 150, "daily_mod" : [ { "timestamp" : "2016-12-01", "impressions" : 5 }, false, { "timestamp" : "2016-12-01" } ] }
如果有人能在表现方面给我一个更好的答案,那么很乐意将其标记为正确的答案。