我有一個mongodb集合,其中每個文檔都有一些屬性和一個utc時間戳。我需要從集合中提取數據並使用聚合框架,因爲我使用集合中的數據在用戶界面上顯示一些圖表。但是,我需要根據用戶的時區進行聚合。假設我知道用戶的時區(通過瀏覽器的請求或其他方式傳遞),是否有任何方法使用聚合框架根據[客戶端]時區進行聚合?如何使用mongod在utc中存儲日期時處理時區問題?
回答
您要求的是目前正在討論的MongoDB issue SERVER-6310。
我在a discussion thread的鏈接中找到此。
這個問題對於按日期進行分組是很常見的,包括SQL數據庫和NoSQL數據庫。事實上,我最近在RavenDB上討論過這個問題。有一個很好的問題描述和一個RavenDB解決方案here。
MongoDB問題討論了一種解決方法,它與我在上面評論中描述的類似。您可以預先計算您感興趣的當地時間,然後將其分組。
用這兩種方法都難以覆蓋世界上的每個時區。您應該決定一小部分對您的用戶羣有意義的目標區域,例如我在RavenDB文章中描述的按部門辦法。
更新:此問題已於2017年7月在MongoDB中解決(版本3.5.11)。該解決方案在上面的第一個鏈接中進行了描述,但簡而言之,它們爲彙總表達式中的日期引入了新的對象格式:{ date: <dateExpression>, timezone: <tzExpression> }
,允許您指定聚合時使用的時區。有關Mongo文檔中的另一個示例,請參見here。
除了Matt Johnson提到的SERVER-6310之外,另一個解決方法是使用$project
運算符來添加或減去UTC時區以將時間「移入正確的本地區域」。原來你可以以毫秒爲單位來增加或減少時間。
例如,假設我有一個名爲orderTime
的日期字段。我想查詢EDT。距離UTC有4個小時。那是4 * 60 * 60 * 1000毫秒。
所以我會接着寫以下投影得到day_ordered
在本地時間爲我所有的記錄:
db.table.aggregate(
{ $project : { orderTimeLocal : { $subtract : [ "$orderTime", 14400000] } } },
{ $project : { day_ordered : { $dayOfYear : "$orderTimeLocal" } } })
謝謝Astral。你的回答是完美的。我真的不想使用地圖縮減只是爲了做一個簡單的時區調整。 – cfchris
這個答案很有意義。如果你想查詢包含EST和EDT的「東部時間」,你會怎麼做? – Joe
根據解釋,不是'「$ lastActivity」'而不是答案中的'「$ orderTime」'? – digitalextremist
每個方法上面建議的工作完全正常,但因爲有一個新版本的MongoDB,從2.6您可以在彙總框架中使用$let
,這將允許您即時創建變量,從而避免在分組之前需要$project
。現在,您可以創建一個帶有$let
的變量,它將保存本地時間,並在$group
運算符中使用它。
是這樣的:
db.test.aggregate([
{$group: {
_id: {
$let: {
vars: {
local_time: { $subtract: ["$date", 10800000]}
},
in: {
$concat: [{$substr: [{$year: "$$local_time"}, 0, 4]},
"-",
{$substr: [{$month: "$$local_time"}, 0, 2]},
"-",
{$substr: [{$dayOfMonth: "$$local_time"}, 0, 2]}]
}
}
},
count: {$sum: 1}
}
}])
注意,使用$let
內的塊/變量的定義,和該塊/變量的值是子表達式"in"
,其中上述定義的VARS是的返回值用過的。
在涉及夏令時的情況下,這也不起作用,因爲您認爲可以減去固定時間,根據當地時間是否在夏令時中,可能會有一小時不同。 –
我在mongoose plugin中發現了一個解決方案來規範存儲日期的時區。
- 1. Java日期處理:在單個類中存儲日期,時間和時區
- 2. 存儲/讀取時區相關問題使用JPA的日期
- 3. 如何在Angular日期過濾器中使用UTC時區?
- 4. 如何使用特定時區的條件獲取UTC存儲日期結果
- 5. 處理日期和時區,使用Zend_Date
- 6. 以UTC存儲日期時間
- 7. 如何在不將日期時間存儲爲TIMESTAMP WITH TIME ZONE的情況下處理時區問題
- 8. 處理時區和日期
- 9. iOS 10:從HealthKit處理日期時與時區問題
- 10. 存儲日期與時區
- 11. 在PHP中處理時區和日期
- 12. 在MongoDB中存儲日期和時區
- 13. 如何在存儲過程中設置日期時間時區
- 14. 處理日期時的時刻日期問題
- 15. 日期時區問題
- 16. javascript日期時區問題
- 17. Android日期時區問題
- 18. 你如何處理時區問題?
- 19. 只有在考慮時區時才能處理保存日期?
- 20. 我如何停止實體框架轉換JSON UTC日期時間,當我想存儲UTC日期時間
- 21. Java 8,Hibernate和PostgreSQL - 如何使用時區存儲日期?
- 22. 在javascript中存儲javascript UTC日期。 php
- 23. 在數據庫中存儲UTC日期時間
- 24. iOS中的日期/時間解析:如何處理(或不處理)時區?
- 25. 以UTC保存日期時間,在Rails中查看/查詢用戶的時區?
- 26. 使用休眠時以UTC時區獲取日期
- 27. 日期和時區問題如何獲取不帶時區的日期?
- 28. 違約日期的時區爲UTC對Jodatime的日期時間
- 29. 如何在MySQL中以正確的方式處理存儲的UTC日期轉換(夏令時)?
- 30. CRM OData日期時間時區問題
你可以更清楚你想做什麼,你爲什麼不能只是轉換到客戶端的時區後聚合?你總是可以使用mapreduce而不是聚合框架 - 它會比較慢,但會允許你需要做任何形式的臨時計算 – Mason
實際上,我需要根據他/她的時區爲用戶生成每週報告。對於報告,我需要使用聚合框架。問題是,我應該在聚合時考慮用戶的時區。我不能在聚合後這樣做,否則會導致錯誤的結果。映射reduce是一個選項,但我需要這個按需,我在查找StackOverflow時發現它不應該用於查詢。我希望會有某種方式。 – Hrishi
我不知道MongoDB能夠很好地回答,但我相信這種方法與我在RavenDB中描述的類似(這裏是http://ravendb.net/kb/61/working-with-date-and -time-in-ravendb#時區轉換),再次在['Foo_ByDate_MultiZone'索引](https://github.com/mj1856/RavenDB-NodaTime/wiki/Indexing-and-Querying)。如果Mongo允許類似的東西,你可以在Map中做這件事,就像我在Raven做的一樣。 –