Есть ли эффективный способ группировки записей по дням в соответствии с конкретным часовым поясом?
Я использую базу данных MongoDB для отслеживания аналитики для приложения. Я пишу приложение Clojure (используя clj-time и Monger) для получения данных из базы данных.
У меня есть коллекция, содержащая записи, такие как
{"_id": ObjectId(...),
timestamp: ISODate("2013-06-01T15:18:37Z"),
device: "04dbf04b6dc0d0a4fd383967b3dc62f50111e07e"}
Каждый отличается device
представляет другого пользователя моего сервиса. Что я хотел бы сделать, это выяснить, сколько (уникальных) пользователей у меня есть каждый день, но с оговоркой, которую я бы хотел, чтобы "день" относился конкретно к часовому поясу США / Центрального района с учетом перехода на летнее время., (Если бы это не было требованием, я думаю, что я мог бы просто сделать что-то вроде $group
а затем distinct
.)
Вот что я делал:
(ns analytics.reporting
(:use [monger.core :only [connect! connect set-db! get-db]]
monger.operators
clj-time.core
clj-time.periodic
clj-time.format)
(:require [monger.collection :as mc]))
(defn to-central
[dt]
(from-time-zone dt (time-zone-for-id "America/Chicago")))
(defn count-distinct
[coll]
(count (distinct coll)))
(defn daily-usage
[ndays]
(let [midnights (map to-central
(reverse (for [offset (map days (range ndays))]
(minus (to-central (today-at 0 0)) offset))))
by-day (for [midnight midnights]
(mc/find-maps "devices" {:timestamp {$gte midnight $lt (plus midnight (days 1))}}))
devices-by-day (map #(map :device %) by-day)
distinct-devices-by-day (map count-distinct devices-by-day)]
distinct-devices-by-day))
Если вы не можете прочитать Clojure, это в основном говорит: получите список самых последних n полуночников в центральном часовом поясе, а затем выполните запросы Mongo, чтобы найти все записи между каждой последовательной парой полуночников. Затем посчитайте количество различных device
в течение каждого дня.
Вот что мне не нравится в этом подходе:
- Выполнение отдельного запроса для каждого дня (я обычно смотрю на 30 дней за раз) кажется неправильным; это то, что должно быть сделано на стороне базы данных, а не на стороне приложения.
- Считая различные
device
Это также должно быть сделано с помощью базы данных. - Мой сервер настроен на часовой пояс UTC, поэтому, если в полночное время по UTC, но до полуночи по центральному времени, последняя запись в этом списке всегда будет нулевой. Это достаточно легко исправить, но я бы предпочел решение, достаточно умное, чтобы предотвратить его.
- Вся эта функция занимает около 500 мсек. Это не ужасно - я единственный, кто запускает запрос, и только один или два раза в день - но кажется, что операция не должна занимать так много времени.
Есть ли способ добавить больше этой логики в запрос MongoDB?
1 ответ
По предложению @WiredPrairie, я просто включил дату в центральном времени в каждую запись, когда добавил ее в базу данных. Тогда я смог использовать тривиальное $group
запрос, чтобы собрать количество записей для каждой даты.