Есть ли эффективный способ группировки записей по дням в соответствии с конкретным часовым поясом?

Я использую базу данных 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в течение каждого дня.

Вот что мне не нравится в этом подходе:

  1. Выполнение отдельного запроса для каждого дня (я обычно смотрю на 30 дней за раз) кажется неправильным; это то, что должно быть сделано на стороне базы данных, а не на стороне приложения.
  2. Считая различные deviceЭто также должно быть сделано с помощью базы данных.
  3. Мой сервер настроен на часовой пояс UTC, поэтому, если в полночное время по UTC, но до полуночи по центральному времени, последняя запись в этом списке всегда будет нулевой. Это достаточно легко исправить, но я бы предпочел решение, достаточно умное, чтобы предотвратить его.
  4. Вся эта функция занимает около 500 мсек. Это не ужасно - я единственный, кто запускает запрос, и только один или два раза в день - но кажется, что операция не должна занимать так много времени.

Есть ли способ добавить больше этой логики в запрос MongoDB?

1 ответ

Решение

По предложению @WiredPrairie, я просто включил дату в центральном времени в каждую запись, когда добавил ее в базу данных. Тогда я смог использовать тривиальное $group запрос, чтобы собрать количество записей для каждой даты.

Другие вопросы по тегам