我有一個包含分析數據的集合(目前擁有超過1000萬個文檔)。從clicks
收集文檔的 例子:重新設計數據庫以消除聚合
{
serverId: 'srv1',
dateVisited: '2014-12-24',
campaignId: 'c1',
...
landingpageClicks: [
{...},
{...}
],
offerTrackings: [
{
amount: 10
},
{
amount: 22
}
{
amount: 18
}
]
}
我需要拉從這個集合的報告。用戶可以請求通過多個字段進行分組,例如按日期組,然後通過serverId
,然後通過campaignId
和報告應該是這樣的:
2014-12-24 | 50 lp clicks | 21 offer clicks | $600 // srv1 + srv2
srv1 | 20 lp clicks | 11 offer clicks | $400 // campaign1 + campaign2
campaign1 | 10 lp clicks | 6 offer clicks | $100
campaign2 | 10 lp clicks | 5 offer clicks | $300
srv2 | 30 lp clicks | 10 offer clicks | $200 // campaign3 + campaign4
campaign3 | 20 lp clicks | 4 offer clicks | $100
campaign4 | 10 lp clicks | 6 offer clicks | $100
目前我使用下面的查詢拉報告,但它是極其緩慢:
db.clicks.aggregate([
{$match: {'_id.dateVisited': '2014-12-24'}},
{$group:{
_id: '$_id.dateVisited',
totalLandingpageClicksCount: {$sum: '$value.landingpageClicksCount'},
totalOfferTrackingsCount: {$sum: '$value.offerTrackingsCount'},
totalOfferTrackingsAmount: {$sum: '$value.offerTrackingsAmount'}
}}
])
我的想法是爲每個可能的字段組合創建單獨的集合,並使用find({<search + group fields>})
而不是聚合。即如果用戶請求特定日期間隔,由serverId
分組,然後由campaignId
報告,下面的查詢將被使用:
//example of doc in dateVisited_serverId collection
{
_id: {
dateVisited: '...',
serverId: '..'
},
value: {
<counts>
}
}
// get stats for date, grouped by serverId
db.dateVisited_serverId.find({
'_id.dateVisited': {
'$gte': dateFrom,
'$lte': dateTo
}
})
//example of doc in dateVisited_serverId_campaignId collection
{
_id: {
dateVisited: '...',
serverId: '..',
campaignId: '..'
},
value: {
<counts>
}
}
// get stats for date, grouped by serverId and then by campaignId
db.dateVisited_serverId_campaignId.find({
dateVisited: {
'$gte': dateFrom,
'$lte': dateTo
},
serverId: {$in: [<server ids from previous query>]}
})
它的工作,但clicks
收集有18場,所以我必須要產生集合來實現我的想法。
這樣我需要爲我的數據庫找到另一個設計。
[更新]真正的文件的例子:
{
"_id": {
"dateVisited": ISODate("2014-11-05T00:00:00.0Z"),
"campaignId": "4c29dc888be98a9488e6876133852c72",
"landingpageId": "c5557aedab04ad1444b0ee28b5ddaab9",
"offerId": null,
"trafficAccountId": "84d06369b9872e9a2685483b7a532a10",
"serverId": "32",
"browser": "Safari",
"platform": "Android",
"c1": "chat",
"c2": "au",
"c3": "12b-ad1a",
"c4": "mtv2",
"city": "Perth",
"country": "Australia",
"deviceType": "mobile",
"isp": "Telstra Internet",
"netspeedId": NumberLong(3),
"set": ""
},
"value": {
"lpCount": 2,
"offersCount": 0,
"grandConversionCount": 0,
"grandConversionAmount": 0
}
}
一天有多少份文件?爲什麼在'_id.dateVisited'上進行分組而不是在'null'或其他常量值上進行分組 - 因爲'$ match',所有文檔都屬於同一個組。與最簡單的情況相比,展示更復雜/更逼真的例子會很好,因爲它對流水線有很大的影響。爲什麼你不使用日期字段的日期?比起一個字符串,它會更快。你有什麼指標,具體是什麼?你需要'_id.dateVisited'上的索引。你能給我們解釋一個緩慢的聚合嗎? – wdberkeley
〜10 000每天。在'_id.dateVisited'上分組 - 因爲我需要按日期分組。在實際收集日期字段中使用。我有'_id.dateVisited'索引 - $匹配工作相當快。但是如果用戶選擇1年作爲日期範圍,那麼$ group必須處理'365 * 1000 =〜3,650,000'個文檔。這是非常緩慢的 –